From 4f8b59932b5efbbb49a0ff211f4d0fa36be0a48d Mon Sep 17 00:00:00 2001 From: Raymond Lai Date: Wed, 5 Aug 2026 00:34:21 +0800 Subject: [PATCH 1/8] Dependent library upgrades + Jetifier ignore list For easing the effort on migrating to SDK 36. Upgraded: - Gradle: 8.14.5 - Kotlin: 2.2.20 - JDK: 21 - Android Gradle Plugin: 8.13.2 - Spotless: 8.9.0 - AndroidX core: 1.16.0 - AndroidX fragment: 1.8.9 - AndroidX appcompat: 1.7.1 - AndroidX annotation: 1.10.0 - AndroidX constraint layout: 2.2.2 - sshj: 0.40.0 - Bouncy castle: 1.85 - slf4j: 2.0.18 - junrar: 8.1.0, also enables support of RARv5 - xz: 1.12 - zip4j: 2.11.6 - logback-classic: 1.6.1 - jsoup: 1.23.1 - gson: 2.14.0 - rxjava: 2.2.21 - acra-core: 5.13.1 - leak-canary-android: 2.14 - okHttp: 5.1.0 - commons-net: 3.13.0 - kotlin-stdlib-jdk8: 2.2.10 - espresso: 3.7.0 - AndroidX Test: 1.7.0 - AndroidX Test extension: 1.3.0 - kotlin-coroutine-test: 1.11.0 - UI automator: 2.4.0 - mockito: 5.23.0 - mockk: 1.14.11 - systembartint: 1.0.4 - awaitility: 4.3.0 - glide: 5.0.5 - apache-mina: 2.2.9 - apache-sshd: 2.19.0 - apache-ftpserver: 1.2.1 - robolectric: 4.15 --- app/build.gradle | 37 +++++--- .../ui/fragments/TabFragmentTest.kt | 2 +- ...va => UnsupportedRarVersionException.java} | 17 +++- .../adapters/ContributorAdapter.kt | 1 + .../filemanager/adapters/LanguageAdapter.kt | 1 + .../asynctasks/compress/ZipHelperCallable.kt | 3 + .../asynchronous/services/ExtractService.java | 6 +- .../extractcontents/helpers/ZipExtractor.kt | 5 +- .../filesystem/files/EncryptDecryptUtils.kt | 1 + .../amaze/filemanager/models/LanguageModel.kt | 1 + .../ui/dialogs/DragAndDropDialog.kt | 4 +- .../fragments/CompressedExplorerFragment.kt | 9 +- .../filemanager/utils/ContextCompatExt.kt | 20 +++++ .../filemanager/utils/FingerprintHandler.kt | 1 + .../asynctasks/compress/RarHelperCallable.kt | 6 +- .../extractcontents/helpers/RarExtractor.kt | 14 ++- app/src/test/AndroidManifest.xml | 2 - .../write/WriteTextFileCallableTest.java | 2 +- .../services/ExtractServiceTest.kt | 7 +- .../services/ftp/FtpReceiverTest.kt | 6 +- .../ftp/NetCopyClientConnectionPoolTest.kt | 20 +++++ .../filesystem/ssh/AbstractSftpServerTest.kt | 8 +- .../filesystem/ssh/test/TestKeyProvider.java | 3 +- .../activities/DatabaseViewerActivityTest.kt | 20 +++++ .../dialogs/AbstractSftpConnectDialogTests.kt | 20 +++++ .../AbstractSftpConnectDialogUiTests.kt | 20 +++++ ...SftpConnectDialogArgumentPopulationTest.kt | 20 +++++ .../ui/dialogs/SftpConnectDialogFtpTest.kt | 20 +++++ .../fragments/TabFragmentRobolectricTest.kt | 20 +++++ .../amaze/filemanager/ui/icons/IconsTest.java | 6 +- .../NotificationConstantsTest.java | 8 +- .../filemanager/utils/NetworkUtilTest.kt | 20 +++++ .../compress/RarHelperCallableTest.kt | 16 +--- .../MultipartRarExtractorTest.kt | 45 +++++----- build.gradle | 36 ++++---- commons_compress_7z/build.gradle | 6 +- .../src/main/AndroidManifest.xml | 4 +- file_operations/build.gradle | 12 +-- file_operations/src/main/AndroidManifest.xml | 2 +- gradle.properties | 51 +++++++++++ gradle/libs.versions.toml | 82 +++++++++--------- gradle/wrapper/gradle-wrapper.jar | Bin 60756 -> 43764 bytes gradle/wrapper/gradle-wrapper.properties | 4 +- gradlew | 41 +++++---- gradlew.bat | 27 +++--- portscanner/build.gradle | 12 +-- .../shadows/ShadowContentResolver.kt | 48 ---------- .../filemanager/shadows/ShadowFileUtils.kt | 3 +- 48 files changed, 475 insertions(+), 244 deletions(-) rename app/src/fdroid/java/com/github/junrar/exception/{UnsupportedRarV5Exception.java => UnsupportedRarVersionException.java} (51%) delete mode 100644 app/src/test/AndroidManifest.xml delete mode 100644 testShared/src/test/java/com/amaze/filemanager/shadows/ShadowContentResolver.kt diff --git a/app/build.gradle b/app/build.gradle index d2e9ad3f05..bd16fcc929 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -8,10 +8,21 @@ apply plugin: 'com.google.devtools.ksp' android { namespace "com.amaze.filemanager" - compileSdk libs.versions.compileSdk.get().toInteger() + compileSdkVersion libs.versions.compileSdk.get().toInteger() packagingOptions { resources { - excludes += ['proguard-project.txt', 'project.properties', 'META-INF/LICENSE.txt', 'META-INF/LICENSE', 'META-INF/NOTICE.txt', 'META-INF/NOTICE', 'META-INF/DEPENDENCIES.txt', 'META-INF/DEPENDENCIES', 'META-INF/versions/9/OSGI-INF/MANIFEST.MF'] + excludes += [ + 'proguard-project.txt', + 'project.properties', + 'META-INF/LICENSE.txt', + 'META-INF/LICENSE.md', + 'META-INF/LICENSE', + 'META-INF/NOTICE.txt', + 'META-INF/NOTICE', + 'META-INF/DEPENDENCIES.txt', + 'META-INF/DEPENDENCIES', + 'META-INF/versions/9/OSGI-INF/MANIFEST.MF' + ] } } @@ -44,7 +55,7 @@ android { debug { applicationIdSuffix ".debug" minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard.cfg' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard.cfg' testProguardFile 'tests-proguard.cfg' buildConfigField "String", "CRYPTO_IV", "\"LxbHiJhhUXcj\"" debuggable true //For "debug" banner on icon @@ -55,7 +66,7 @@ android { signingConfig signingConfigs.release minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard.cfg' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard.cfg' buildConfigField "String", "CRYPTO_IV", "\"LxbHiJhhUXcj\"" } } @@ -92,12 +103,8 @@ android { } compileOptions { - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 - } - - kotlinOptions { - jvmTarget = '17' + sourceCompatibility JavaVersion.VERSION_21 + targetCompatibility JavaVersion.VERSION_21 } testOptions { @@ -131,6 +138,7 @@ dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') implementation libs.systembarTint + implementation libs.androidX.activity implementation libs.androidX.vectordrawable.animated implementation libs.androidX.legacySupportV13 implementation libs.androidX.material @@ -150,6 +158,7 @@ dependencies { ksp libs.androidX.annotation //For tests + kspTest libs.auto.service testImplementation libs.junit//tests the app logic testImplementation libs.robolectric//tests android interaction testImplementation libs.robolectric.shadows.httpclient//tests android interaction @@ -162,14 +171,15 @@ dependencies { testImplementation libs.mockito.inline testImplementation libs.mockito.kotlin testImplementation libs.apache.sshd + testImplementation libs.apache.sshd.scp + testImplementation libs.apache.sshd.sftp testImplementation libs.awaitility testImplementation libs.jsoup testImplementation libs.room.migration testImplementation libs.mockk testImplementation libs.kotlin.coroutine.test testImplementation libs.androidX.core.testing - kspTest libs.auto.service - testImplementation 'ch.qos.logback:logback-classic:1.4.14' + testImplementation libs.logback.classic androidTestImplementation libs.junit //tests the app logic androidTestImplementation libs.androidX.test.expresso @@ -260,7 +270,7 @@ dependencies { } kotlin { - jvmToolchain(17) + jvmToolchain(21) } configurations.configureEach { @@ -268,6 +278,7 @@ configurations.configureEach { dependencySubstitution { substitute module("commons-logging:commons-logging-api:1.1") using module("commons-logging:commons-logging:1.1.1") substitute module("com.android.support:support-annotations:27.1.1") using module("com.android.support:support-annotations:27.0.2") + substitute module("org.bouncycastle:bcprov-jdk18on:1.80.2") using module("org.bouncycastle:bcprov-jdk18on:1.85") // These two lines are added to prevent possible class clashes between awaitility (which uses hamcrest 2.1) and junit (which uses hamcrest 1.3). substitute module('org.hamcrest:hamcrest-core:1.3') using module("org.hamcrest:hamcrest:2.1") substitute module('org.hamcrest:hamcrest-library:1.3') using module("org.hamcrest:hamcrest:2.1") diff --git a/app/src/androidTest/java/com/amaze/filemanager/ui/fragments/TabFragmentTest.kt b/app/src/androidTest/java/com/amaze/filemanager/ui/fragments/TabFragmentTest.kt index d9e675b581..bdb4937464 100644 --- a/app/src/androidTest/java/com/amaze/filemanager/ui/fragments/TabFragmentTest.kt +++ b/app/src/androidTest/java/com/amaze/filemanager/ui/fragments/TabFragmentTest.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2025 Arpit Khurana , Vishal Nehra , + * Copyright (C) 2014-2026 Arpit Khurana , Vishal Nehra , * Emmanuel Messulam, Raymond Lai and Contributors. * * This file is part of Amaze File Manager. diff --git a/app/src/fdroid/java/com/github/junrar/exception/UnsupportedRarV5Exception.java b/app/src/fdroid/java/com/github/junrar/exception/UnsupportedRarVersionException.java similarity index 51% rename from app/src/fdroid/java/com/github/junrar/exception/UnsupportedRarV5Exception.java rename to app/src/fdroid/java/com/github/junrar/exception/UnsupportedRarVersionException.java index 4ed70a93de..789412c242 100644 --- a/app/src/fdroid/java/com/github/junrar/exception/UnsupportedRarV5Exception.java +++ b/app/src/fdroid/java/com/github/junrar/exception/UnsupportedRarVersionException.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2014-2024 Arpit Khurana , Vishal Nehra , + * Copyright (C) 2014-2026 Arpit Khurana , Vishal Nehra , * Emmanuel Messulam, Raymond Lai and Contributors. * * This file is part of Amaze File Manager. @@ -20,10 +20,19 @@ package com.github.junrar.exception; -public class UnsupportedRarV5Exception extends Exception { - public UnsupportedRarV5Exception(Throwable cause) { +/** + * Thrown when the archive signature names a RAR format this library cannot read: a future format + * version byte ({@code 0x02}..{@code 0x04}) that the library predates (unrar {@code RARFMT_FUTURE}, + * {@code d861246:archive.cpp:122,178-181}: "so we can return a sensible warning in case we'll want + * to change the archive format sometimes in the future"). The ancient RAR 1.4 format (marker {@code + * 52 45 7e 5e}, unrar {@code RARFMT14}) no longer throws this -- {@code Archive} reads its headers + * through a dedicated loop (P1, issue #293). Distinct from {@link BadRarArchiveException} (no valid + * signature at all). + */ +public class UnsupportedRarVersionException extends Exception { + public UnsupportedRarVersionException(Throwable cause) { super(cause); } - public UnsupportedRarV5Exception() {} + public UnsupportedRarVersionException() {} } diff --git a/app/src/main/java/com/amaze/filemanager/adapters/ContributorAdapter.kt b/app/src/main/java/com/amaze/filemanager/adapters/ContributorAdapter.kt index 80fc31bb2b..1c3c0a8b5a 100644 --- a/app/src/main/java/com/amaze/filemanager/adapters/ContributorAdapter.kt +++ b/app/src/main/java/com/amaze/filemanager/adapters/ContributorAdapter.kt @@ -17,6 +17,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + package com.amaze.filemanager.adapters import android.view.LayoutInflater diff --git a/app/src/main/java/com/amaze/filemanager/adapters/LanguageAdapter.kt b/app/src/main/java/com/amaze/filemanager/adapters/LanguageAdapter.kt index 3b1a252d32..ef14572701 100644 --- a/app/src/main/java/com/amaze/filemanager/adapters/LanguageAdapter.kt +++ b/app/src/main/java/com/amaze/filemanager/adapters/LanguageAdapter.kt @@ -17,6 +17,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + package com.amaze.filemanager.adapters import android.view.LayoutInflater diff --git a/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/compress/ZipHelperCallable.kt b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/compress/ZipHelperCallable.kt index e8387d80b2..f3787bdeef 100644 --- a/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/compress/ZipHelperCallable.kt +++ b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/compress/ZipHelperCallable.kt @@ -50,6 +50,9 @@ class ZipHelperCallable( try { fileLocation.path?.run { val zipfile = ZipFile(fileLocation.path) + if (!zipfile.isValidZipFile || zipfile.file.length() == 0L) { + throw ZipException("Zero byte or corrupt zip file") + } val wholelist = filterValidEntryList(zipfile) val strings = ArrayList() for (entry in wholelist) { diff --git a/app/src/main/java/com/amaze/filemanager/asynchronous/services/ExtractService.java b/app/src/main/java/com/amaze/filemanager/asynchronous/services/ExtractService.java index 12b64b9953..b48a9d44f9 100644 --- a/app/src/main/java/com/amaze/filemanager/asynchronous/services/ExtractService.java +++ b/app/src/main/java/com/amaze/filemanager/asynchronous/services/ExtractService.java @@ -44,7 +44,7 @@ import com.amaze.filemanager.utils.DatapointParcelable; import com.amaze.filemanager.utils.ObtainableServiceBinder; import com.amaze.filemanager.utils.ProgressHandler; -import com.github.junrar.exception.UnsupportedRarV5Exception; +import com.github.junrar.exception.UnsupportedRarVersionException; import android.app.PendingIntent; import android.content.BroadcastReceiver; @@ -364,8 +364,8 @@ public boolean isCancelled() { paused = true; publishProgress(e); } else if (e.getCause() != null - && UnsupportedRarV5Exception.class.isAssignableFrom(e.getCause().getClass())) { - LOG.error("RAR " + compressedPath + " is unsupported V5 archive", e); + && UnsupportedRarVersionException.class.isAssignableFrom(e.getCause().getClass())) { + LOG.error(compressedPath + " is an unsupported RAR archive", e); AppConfig.toast( getApplicationContext(), extractService.getString(R.string.error_unsupported_v5_rar, compressedPath)); diff --git a/app/src/main/java/com/amaze/filemanager/filesystem/compressed/extractcontents/helpers/ZipExtractor.kt b/app/src/main/java/com/amaze/filemanager/filesystem/compressed/extractcontents/helpers/ZipExtractor.kt index 159cf3d772..50e2aa88c7 100644 --- a/app/src/main/java/com/amaze/filemanager/filesystem/compressed/extractcontents/helpers/ZipExtractor.kt +++ b/app/src/main/java/com/amaze/filemanager/filesystem/compressed/extractcontents/helpers/ZipExtractor.kt @@ -68,7 +68,7 @@ class ZipExtractor( invalidArchiveEntries.add(fileHeader.fileName) } } - if (entriesToExtract.size > 0) { + if (entriesToExtract.isNotEmpty()) { listener.onStart(totalBytes, entriesToExtract[0].fileName) for (entry in entriesToExtract) { if (!listener.isCancelled) { @@ -77,6 +77,9 @@ class ZipExtractor( } } } else { + if (zipfile.file.length() == 0L) { + throw ZipException("Zero byte or corrupt zip file") + } throw EmptyArchiveNotice() } listener.onFinish() diff --git a/app/src/main/java/com/amaze/filemanager/filesystem/files/EncryptDecryptUtils.kt b/app/src/main/java/com/amaze/filemanager/filesystem/files/EncryptDecryptUtils.kt index a389000915..d1fe98186b 100644 --- a/app/src/main/java/com/amaze/filemanager/filesystem/files/EncryptDecryptUtils.kt +++ b/app/src/main/java/com/amaze/filemanager/filesystem/files/EncryptDecryptUtils.kt @@ -17,6 +17,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + package com.amaze.filemanager.filesystem.files import android.content.Context diff --git a/app/src/main/java/com/amaze/filemanager/models/LanguageModel.kt b/app/src/main/java/com/amaze/filemanager/models/LanguageModel.kt index 1903454460..8c468016fe 100644 --- a/app/src/main/java/com/amaze/filemanager/models/LanguageModel.kt +++ b/app/src/main/java/com/amaze/filemanager/models/LanguageModel.kt @@ -17,6 +17,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + package com.amaze.filemanager.models data class LanguageModel(var title: String, var description: String) diff --git a/app/src/main/java/com/amaze/filemanager/ui/dialogs/DragAndDropDialog.kt b/app/src/main/java/com/amaze/filemanager/ui/dialogs/DragAndDropDialog.kt index f532ca4a7d..8d4103db6b 100644 --- a/app/src/main/java/com/amaze/filemanager/ui/dialogs/DragAndDropDialog.kt +++ b/app/src/main/java/com/amaze/filemanager/ui/dialogs/DragAndDropDialog.kt @@ -135,7 +135,7 @@ class DragAndDropDialog : DialogFragment() { override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { safeLet( context, - mainActivity?.appTheme?.getMaterialDialogTheme(), + mainActivity?.appTheme?.materialDialogTheme, mainActivity?.accent, pasteLocation, operationFiles, @@ -146,7 +146,7 @@ class DragAndDropDialog : DialogFragment() { .title(getString(R.string.choose_operation)) .customView(R.layout.dialog_drag_drop, true) .theme(dialogTheme) - .negativeText(getString(R.string.cancel).toUpperCase()) + .negativeText(getString(R.string.cancel).uppercase()) .negativeColor(accent) .cancelable(false) .onNeutral { _: MaterialDialog?, _: DialogAction? -> diff --git a/app/src/main/java/com/amaze/filemanager/ui/fragments/CompressedExplorerFragment.kt b/app/src/main/java/com/amaze/filemanager/ui/fragments/CompressedExplorerFragment.kt index dacea24693..d70d9fa02b 100644 --- a/app/src/main/java/com/amaze/filemanager/ui/fragments/CompressedExplorerFragment.kt +++ b/app/src/main/java/com/amaze/filemanager/ui/fragments/CompressedExplorerFragment.kt @@ -79,7 +79,7 @@ import com.amaze.filemanager.ui.views.DividerItemDecoration import com.amaze.filemanager.ui.views.FastScroller import com.amaze.filemanager.utils.BottomBarButtonPath import com.amaze.filemanager.utils.Utils -import com.github.junrar.exception.UnsupportedRarV5Exception +import com.github.junrar.exception.UnsupportedRarVersionException import com.google.android.material.appbar.AppBarLayout import com.google.android.material.appbar.AppBarLayout.OnOffsetChangedListener import io.reactivex.Flowable @@ -656,7 +656,10 @@ class CompressedExplorerFragment : Fragment(), BottomBarButtonPath { private fun archiveCorruptOrUnsupportedToast(e: Throwable?) { @StringRes val msg: Int = - if (e?.cause?.javaClass is UnsupportedRarV5Exception) { + if (UnsupportedRarVersionException::class.java.isAssignableFrom( + e?.cause?.javaClass, + ) + ) { R.string.error_unsupported_v5_rar } else { R.string.archive_unsupported_or_corrupt @@ -774,7 +777,7 @@ class CompressedExplorerFragment : Fragment(), BottomBarButtonPath { get() = isRoot(relativeDirectory) private fun isRoot(folder: String?): Boolean { - return folder == null || folder.isEmpty() + return folder.isNullOrEmpty() } /** diff --git a/app/src/main/java/com/amaze/filemanager/utils/ContextCompatExt.kt b/app/src/main/java/com/amaze/filemanager/utils/ContextCompatExt.kt index 50223c6121..83056c3315 100644 --- a/app/src/main/java/com/amaze/filemanager/utils/ContextCompatExt.kt +++ b/app/src/main/java/com/amaze/filemanager/utils/ContextCompatExt.kt @@ -1,3 +1,23 @@ +/* + * Copyright (C) 2014-2026 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai and Contributors. + * + * This file is part of Amaze File Manager. + * + * Amaze File Manager is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package com.amaze.filemanager.utils import android.annotation.SuppressLint diff --git a/app/src/main/java/com/amaze/filemanager/utils/FingerprintHandler.kt b/app/src/main/java/com/amaze/filemanager/utils/FingerprintHandler.kt index 45f109f483..97efb65ad6 100644 --- a/app/src/main/java/com/amaze/filemanager/utils/FingerprintHandler.kt +++ b/app/src/main/java/com/amaze/filemanager/utils/FingerprintHandler.kt @@ -17,6 +17,7 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ + package com.amaze.filemanager.utils import android.Manifest diff --git a/app/src/play/java/com/amaze/filemanager/asynchronous/asynctasks/compress/RarHelperCallable.kt b/app/src/play/java/com/amaze/filemanager/asynchronous/asynctasks/compress/RarHelperCallable.kt index 62b35e473a..6d738cfce1 100644 --- a/app/src/play/java/com/amaze/filemanager/asynchronous/asynctasks/compress/RarHelperCallable.kt +++ b/app/src/play/java/com/amaze/filemanager/asynchronous/asynctasks/compress/RarHelperCallable.kt @@ -25,7 +25,7 @@ import com.amaze.filemanager.filesystem.compressed.CompressedHelper import com.amaze.filemanager.filesystem.compressed.showcontents.helpers.RarDecompressor.Companion.convertName import com.github.junrar.Archive import com.github.junrar.exception.RarException -import com.github.junrar.exception.UnsupportedRarV5Exception +import com.github.junrar.exception.UnsupportedRarVersionException import org.apache.commons.compress.archivers.ArchiveException import java.io.File import java.io.FileNotFoundException @@ -77,8 +77,8 @@ class RarHelperCallable( ) } } - } catch (e: UnsupportedRarV5Exception) { - throw ArchiveException("RAR v5 archives are not supported", e) + } catch (e: UnsupportedRarVersionException) { + throw ArchiveException("RAR archive version not supported", e) } catch (e: FileNotFoundException) { throw ArchiveException("First part of multipart archive not found", e) } catch (e: RarException) { diff --git a/app/src/play/java/com/amaze/filemanager/filesystem/compressed/extractcontents/helpers/RarExtractor.kt b/app/src/play/java/com/amaze/filemanager/filesystem/compressed/extractcontents/helpers/RarExtractor.kt index 3cb5ebe485..c4ef3d2988 100644 --- a/app/src/play/java/com/amaze/filemanager/filesystem/compressed/extractcontents/helpers/RarExtractor.kt +++ b/app/src/play/java/com/amaze/filemanager/filesystem/compressed/extractcontents/helpers/RarExtractor.kt @@ -32,10 +32,11 @@ import com.amaze.filemanager.filesystem.compressed.extractcontents.Extractor import com.amaze.filemanager.filesystem.compressed.isPasswordProtectedCompat import com.amaze.filemanager.filesystem.files.GenericCopyUtil import com.github.junrar.Archive +import com.github.junrar.exception.BadRarArchiveException import com.github.junrar.exception.CorruptHeaderException import com.github.junrar.exception.MainHeaderNullException import com.github.junrar.exception.RarException -import com.github.junrar.exception.UnsupportedRarV5Exception +import com.github.junrar.exception.UnsupportedRarVersionException import com.github.junrar.rarfile.FileHeader import org.apache.commons.compress.PasswordRequiredException import java.io.BufferedInputStream @@ -58,13 +59,14 @@ class RarExtractor( override fun extractWithFilter(filter: Filter) { try { var totalBytes: Long = 0 + val file = File(filePath) val rarFile = runCatching { ArchivePasswordCache.getInstance()[filePath]?.let { - Archive(File(filePath), it).also { archive -> + Archive(file, it).also { archive -> archive.password = it } - } ?: Archive(File(filePath)) + } ?: Archive(file) }.onFailure { when { // Hack. CorruptHeaderException will throw if archive is really corrupt or @@ -78,7 +80,11 @@ class RarExtractor( throw BadArchiveNotice(it) } - UnsupportedRarV5Exception::class.java.isAssignableFrom(it::class.java) -> { + BadRarArchiveException::class.java.isAssignableFrom(it::class.java) -> { + throw BadArchiveNotice(it) + } + + UnsupportedRarVersionException::class.java.isAssignableFrom(it::class.java) -> { throw it } diff --git a/app/src/test/AndroidManifest.xml b/app/src/test/AndroidManifest.xml deleted file mode 100644 index 568741e54f..0000000000 --- a/app/src/test/AndroidManifest.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/texteditor/write/WriteTextFileCallableTest.java b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/texteditor/write/WriteTextFileCallableTest.java index 8fcc850e5d..156314e0cd 100644 --- a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/texteditor/write/WriteTextFileCallableTest.java +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/texteditor/write/WriteTextFileCallableTest.java @@ -44,13 +44,13 @@ import org.robolectric.annotation.Implementation; import org.robolectric.annotation.Implements; import org.robolectric.shadow.api.Shadow; +import org.robolectric.shadows.ShadowContentResolver; import com.amaze.filemanager.fileoperations.exceptions.ShellNotRunningException; import com.amaze.filemanager.fileoperations.exceptions.StreamNotFoundException; import com.amaze.filemanager.filesystem.EditableFileAbstraction; import com.amaze.filemanager.filesystem.FileUtil; import com.amaze.filemanager.filesystem.root.ConcatenateFileCommand; -import com.amaze.filemanager.shadows.ShadowContentResolver; import com.amaze.filemanager.shadows.ShadowMultiDex; import android.content.ContentResolver; diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/services/ExtractServiceTest.kt b/app/src/test/java/com/amaze/filemanager/asynchronous/services/ExtractServiceTest.kt index 7bdbbf94dc..94259d4102 100644 --- a/app/src/test/java/com/amaze/filemanager/asynchronous/services/ExtractServiceTest.kt +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/services/ExtractServiceTest.kt @@ -465,11 +465,8 @@ class ExtractServiceTest { if (BuildConfig.FLAVOR == "play") { performTest(multiVolumeRarFileV5Part1) ShadowLooper.idleMainLooper() - await() - .atMost(10, TimeUnit.SECONDS) - .until { - ShadowToast.getLatestToast() != null - } + assertNull(ShadowToast.getLatestToast()) + assertNull(ShadowToast.getTextOfLatestToast()) } } diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/services/ftp/FtpReceiverTest.kt b/app/src/test/java/com/amaze/filemanager/asynchronous/services/ftp/FtpReceiverTest.kt index b08a421056..02d132b982 100644 --- a/app/src/test/java/com/amaze/filemanager/asynchronous/services/ftp/FtpReceiverTest.kt +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/services/ftp/FtpReceiverTest.kt @@ -29,7 +29,6 @@ import android.os.Build.VERSION_CODES.P import androidx.test.ext.junit.runners.AndroidJUnit4 import com.amaze.filemanager.application.AppConfig import com.amaze.filemanager.shadows.ShadowMultiDex -import io.mockk.Called import io.mockk.every import io.mockk.mockkObject import io.mockk.slot @@ -109,8 +108,11 @@ class FtpReceiverTest { val intent = Intent(FtpService.ACTION_START_FTPSERVER) receiver.onReceive(spy, intent) + verify(exactly = 0) { + spy.startService(capturedIntent.captured) + } + verify { - spy.startService(capturedIntent.captured)?.wasNot(Called) spy.startForegroundService(capturedIntent.captured) } } diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/ftp/NetCopyClientConnectionPoolTest.kt b/app/src/test/java/com/amaze/filemanager/filesystem/ftp/NetCopyClientConnectionPoolTest.kt index 00823c7b8c..8d96019571 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/ftp/NetCopyClientConnectionPoolTest.kt +++ b/app/src/test/java/com/amaze/filemanager/filesystem/ftp/NetCopyClientConnectionPoolTest.kt @@ -1,3 +1,23 @@ +/* + * Copyright (C) 2014-2026 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai and Contributors. + * + * This file is part of Amaze File Manager. + * + * Amaze File Manager is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package com.amaze.filemanager.filesystem.ftp import org.apache.commons.net.ftp.FTPSClient diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/ssh/AbstractSftpServerTest.kt b/app/src/test/java/com/amaze/filemanager/filesystem/ssh/AbstractSftpServerTest.kt index a7cce7c3f1..708805e08d 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/ssh/AbstractSftpServerTest.kt +++ b/app/src/test/java/com/amaze/filemanager/filesystem/ssh/AbstractSftpServerTest.kt @@ -37,17 +37,15 @@ import com.amaze.filemanager.utils.PasswordUtil import io.reactivex.android.plugins.RxAndroidPlugins import io.reactivex.plugins.RxJavaPlugins import io.reactivex.schedulers.Schedulers -import org.apache.sshd.common.NamedFactory import org.apache.sshd.common.config.keys.KeyUtils import org.apache.sshd.common.file.FileSystemFactory import org.apache.sshd.common.file.virtualfs.VirtualFileSystemFactory -import org.apache.sshd.server.Command +import org.apache.sshd.scp.server.ScpCommandFactory import org.apache.sshd.server.SshServer import org.apache.sshd.server.auth.password.PasswordAuthenticator import org.apache.sshd.server.auth.pubkey.AcceptAllPublickeyAuthenticator -import org.apache.sshd.server.scp.ScpCommandFactory import org.apache.sshd.server.session.ServerSession -import org.apache.sshd.server.subsystem.sftp.SftpSubsystemFactory +import org.apache.sshd.sftp.server.SftpSubsystemFactory import org.junit.After import org.junit.Before import org.junit.BeforeClass @@ -132,7 +130,7 @@ abstract class AbstractSftpServerTest { server.host = HOST server.keyPairProvider = hostKeyProvider server.commandFactory = ScpCommandFactory() - server.subsystemFactories = listOf>(SftpSubsystemFactory()) + server.subsystemFactories = listOf(SftpSubsystemFactory()) server.passwordAuthenticator = PasswordAuthenticator { username: String, password: String, _: ServerSession? -> username == USERNAME && password == PASSWORD diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/ssh/test/TestKeyProvider.java b/app/src/test/java/com/amaze/filemanager/filesystem/ssh/test/TestKeyProvider.java index b76067d0fa..20ff158074 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/ssh/test/TestKeyProvider.java +++ b/app/src/test/java/com/amaze/filemanager/filesystem/ssh/test/TestKeyProvider.java @@ -29,6 +29,7 @@ import java.util.Collections; import org.apache.sshd.common.keyprovider.KeyPairProvider; +import org.apache.sshd.common.session.SessionContext; import net.schmizz.sshj.common.KeyType; import net.schmizz.sshj.userauth.keyprovider.KeyProvider; @@ -44,7 +45,7 @@ public TestKeyProvider() throws Exception { } @Override - public Iterable loadKeys() { + public Iterable loadKeys(SessionContext sessionContext) { return Collections.singleton(keyPair); } diff --git a/app/src/test/java/com/amaze/filemanager/ui/activities/DatabaseViewerActivityTest.kt b/app/src/test/java/com/amaze/filemanager/ui/activities/DatabaseViewerActivityTest.kt index 55a7909931..24f0d60582 100644 --- a/app/src/test/java/com/amaze/filemanager/ui/activities/DatabaseViewerActivityTest.kt +++ b/app/src/test/java/com/amaze/filemanager/ui/activities/DatabaseViewerActivityTest.kt @@ -1,3 +1,23 @@ +/* + * Copyright (C) 2014-2026 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai and Contributors. + * + * This file is part of Amaze File Manager. + * + * Amaze File Manager is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package com.amaze.filemanager.ui.activities import android.content.Intent diff --git a/app/src/test/java/com/amaze/filemanager/ui/dialogs/AbstractSftpConnectDialogTests.kt b/app/src/test/java/com/amaze/filemanager/ui/dialogs/AbstractSftpConnectDialogTests.kt index c1181a6e61..a5013f3229 100644 --- a/app/src/test/java/com/amaze/filemanager/ui/dialogs/AbstractSftpConnectDialogTests.kt +++ b/app/src/test/java/com/amaze/filemanager/ui/dialogs/AbstractSftpConnectDialogTests.kt @@ -1,3 +1,23 @@ +/* + * Copyright (C) 2014-2026 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai and Contributors. + * + * This file is part of Amaze File Manager. + * + * Amaze File Manager is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package com.amaze.filemanager.ui.dialogs import com.amaze.filemanager.ui.activities.AbstractMainActivityTestBase diff --git a/app/src/test/java/com/amaze/filemanager/ui/dialogs/AbstractSftpConnectDialogUiTests.kt b/app/src/test/java/com/amaze/filemanager/ui/dialogs/AbstractSftpConnectDialogUiTests.kt index 1f5d7629aa..20673f4517 100644 --- a/app/src/test/java/com/amaze/filemanager/ui/dialogs/AbstractSftpConnectDialogUiTests.kt +++ b/app/src/test/java/com/amaze/filemanager/ui/dialogs/AbstractSftpConnectDialogUiTests.kt @@ -1,3 +1,23 @@ +/* + * Copyright (C) 2014-2026 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai and Contributors. + * + * This file is part of Amaze File Manager. + * + * Amaze File Manager is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package com.amaze.filemanager.ui.dialogs import android.os.Bundle diff --git a/app/src/test/java/com/amaze/filemanager/ui/dialogs/SftpConnectDialogArgumentPopulationTest.kt b/app/src/test/java/com/amaze/filemanager/ui/dialogs/SftpConnectDialogArgumentPopulationTest.kt index a2a1e42705..3aab5209e0 100644 --- a/app/src/test/java/com/amaze/filemanager/ui/dialogs/SftpConnectDialogArgumentPopulationTest.kt +++ b/app/src/test/java/com/amaze/filemanager/ui/dialogs/SftpConnectDialogArgumentPopulationTest.kt @@ -1,3 +1,23 @@ +/* + * Copyright (C) 2014-2026 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai and Contributors. + * + * This file is part of Amaze File Manager. + * + * Amaze File Manager is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package com.amaze.filemanager.ui.dialogs import android.os.Bundle diff --git a/app/src/test/java/com/amaze/filemanager/ui/dialogs/SftpConnectDialogFtpTest.kt b/app/src/test/java/com/amaze/filemanager/ui/dialogs/SftpConnectDialogFtpTest.kt index 7fcd0855d7..0d90e72ac2 100644 --- a/app/src/test/java/com/amaze/filemanager/ui/dialogs/SftpConnectDialogFtpTest.kt +++ b/app/src/test/java/com/amaze/filemanager/ui/dialogs/SftpConnectDialogFtpTest.kt @@ -1,3 +1,23 @@ +/* + * Copyright (C) 2014-2026 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai and Contributors. + * + * This file is part of Amaze File Manager. + * + * Amaze File Manager is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package com.amaze.filemanager.ui.dialogs import android.os.Bundle diff --git a/app/src/test/java/com/amaze/filemanager/ui/fragments/TabFragmentRobolectricTest.kt b/app/src/test/java/com/amaze/filemanager/ui/fragments/TabFragmentRobolectricTest.kt index c78d0c910d..d8c31cb9a6 100644 --- a/app/src/test/java/com/amaze/filemanager/ui/fragments/TabFragmentRobolectricTest.kt +++ b/app/src/test/java/com/amaze/filemanager/ui/fragments/TabFragmentRobolectricTest.kt @@ -1,3 +1,23 @@ +/* + * Copyright (C) 2014-2026 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai and Contributors. + * + * This file is part of Amaze File Manager. + * + * Amaze File Manager is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package com.amaze.filemanager.ui.fragments import androidx.test.core.app.ActivityScenario diff --git a/app/src/test/java/com/amaze/filemanager/ui/icons/IconsTest.java b/app/src/test/java/com/amaze/filemanager/ui/icons/IconsTest.java index 117e3da274..39ace0bde4 100644 --- a/app/src/test/java/com/amaze/filemanager/ui/icons/IconsTest.java +++ b/app/src/test/java/com/amaze/filemanager/ui/icons/IconsTest.java @@ -48,9 +48,9 @@ public class IconsTest { public void setUp() { // By default Robolectric's MimeTypeMap is empty, we need to populate them ShadowMimeTypeMap mimeTypeMap = Shadows.shadowOf(MimeTypeMap.getSingleton()); - mimeTypeMap.addExtensionMimeTypMapping("zip", "application/zip"); - mimeTypeMap.addExtensionMimeTypMapping("rar", "application/x-rar-compressed"); - mimeTypeMap.addExtensionMimeTypMapping("tar", "application/x-tar"); + mimeTypeMap.addExtensionMimeTypeMapping("zip", "application/zip"); + mimeTypeMap.addExtensionMimeTypeMapping("rar", "application/x-rar-compressed"); + mimeTypeMap.addExtensionMimeTypeMapping("tar", "application/x-tar"); } @Test diff --git a/app/src/test/java/com/amaze/filemanager/ui/notifications/NotificationConstantsTest.java b/app/src/test/java/com/amaze/filemanager/ui/notifications/NotificationConstantsTest.java index 78468e5358..f9c5e4b8ea 100644 --- a/app/src/test/java/com/amaze/filemanager/ui/notifications/NotificationConstantsTest.java +++ b/app/src/test/java/com/amaze/filemanager/ui/notifications/NotificationConstantsTest.java @@ -140,10 +140,10 @@ public void testFtpNotification() { public void testCreateNormalChannel() { NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_NORMAL_ID); NotificationConstants.setMetadata(context, builder, TYPE_NORMAL); - List channels = shadowNotificationManager.getNotificationChannels(); + List channels = shadowNotificationManager.getNotificationChannels(); assertNotNull(channels); assertEquals(1, channels.size()); - NotificationChannel channel = (NotificationChannel) channels.get(0); + NotificationChannel channel = channels.get(0); assertEquals(IMPORTANCE_MIN, channel.getImportance()); assertEquals(CHANNEL_NORMAL_ID, channel.getId()); assertEquals(context.getString(R.string.channel_name_normal), channel.getName()); @@ -155,10 +155,10 @@ public void testCreateNormalChannel() { public void testCreateFtpChannel() { NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_FTP_ID); NotificationConstants.setMetadata(context, builder, TYPE_FTP); - List channels = shadowNotificationManager.getNotificationChannels(); + List channels = shadowNotificationManager.getNotificationChannels(); assertNotNull(channels); assertEquals(1, channels.size()); - NotificationChannel channel = (NotificationChannel) channels.get(0); + NotificationChannel channel = channels.get(0); assertEquals(IMPORTANCE_HIGH, channel.getImportance()); assertEquals(CHANNEL_FTP_ID, channel.getId()); assertEquals(context.getString(R.string.channel_name_ftp), channel.getName()); diff --git a/app/src/test/java/com/amaze/filemanager/utils/NetworkUtilTest.kt b/app/src/test/java/com/amaze/filemanager/utils/NetworkUtilTest.kt index 5f2a071a64..05e452debb 100644 --- a/app/src/test/java/com/amaze/filemanager/utils/NetworkUtilTest.kt +++ b/app/src/test/java/com/amaze/filemanager/utils/NetworkUtilTest.kt @@ -1,3 +1,23 @@ +/* + * Copyright (C) 2014-2026 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai and Contributors. + * + * This file is part of Amaze File Manager. + * + * Amaze File Manager is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package com.amaze.filemanager.utils import android.app.Service diff --git a/app/src/testPlay/java/com/amaze/filemanager/asynchronous/asynctasks/compress/RarHelperCallableTest.kt b/app/src/testPlay/java/com/amaze/filemanager/asynchronous/asynctasks/compress/RarHelperCallableTest.kt index 3f4bc56889..51faea35ad 100644 --- a/app/src/testPlay/java/com/amaze/filemanager/asynchronous/asynctasks/compress/RarHelperCallableTest.kt +++ b/app/src/testPlay/java/com/amaze/filemanager/asynchronous/asynctasks/compress/RarHelperCallableTest.kt @@ -21,11 +21,8 @@ package com.amaze.filemanager.asynchronous.asynctasks.compress import android.os.Environment -import com.github.junrar.exception.UnsupportedRarV5Exception -import org.apache.commons.compress.archivers.ArchiveException import org.junit.Assert.assertEquals import org.junit.Assert.assertNotNull -import org.junit.Assert.assertNull import org.junit.Test import java.io.File @@ -72,15 +69,10 @@ class RarHelperCallableTest : AbstractCompressedHelperCallableArchiveTest() { "", false, ) - val result = - try { - callable.call() - } catch (exception: Throwable) { - assertEquals(ArchiveException::class.java, exception.javaClass) - assertEquals(UnsupportedRarV5Exception::class.java, exception.cause!!.javaClass) - null - } - assertNull(result) + val result = callable.call() + assertNotNull(result) + assertEquals(1, result.size) + assertEquals("test.bin", result.first().name) } override fun doCreateCallable( diff --git a/app/src/testPlay/java/com/amaze/filemanager/filesystem/compressed/extractcontents/MultipartRarExtractorTest.kt b/app/src/testPlay/java/com/amaze/filemanager/filesystem/compressed/extractcontents/MultipartRarExtractorTest.kt index e2538e9cf8..c811673e18 100644 --- a/app/src/testPlay/java/com/amaze/filemanager/filesystem/compressed/extractcontents/MultipartRarExtractorTest.kt +++ b/app/src/testPlay/java/com/amaze/filemanager/filesystem/compressed/extractcontents/MultipartRarExtractorTest.kt @@ -28,8 +28,8 @@ import com.amaze.filemanager.asynchronous.management.ServiceWatcherUtil import com.amaze.filemanager.filesystem.compressed.extractcontents.Extractor.OnUpdate import com.amaze.filemanager.filesystem.compressed.extractcontents.helpers.RarExtractor import com.amaze.filemanager.shadows.ShadowMultiDex -import com.github.junrar.exception.UnsupportedRarV5Exception -import org.junit.Assert +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -38,7 +38,6 @@ import org.robolectric.shadows.ShadowEnvironment import java.io.File import java.io.FileInputStream import java.io.FileOutputStream -import java.io.IOException import java.util.concurrent.CountDownLatch @RunWith(AndroidJUnit4::class) @@ -87,8 +86,8 @@ class MultipartRarExtractorTest { override fun onFinish() { latch.countDown() val verify = File(Environment.getExternalStorageDirectory(), "test.bin") - Assert.assertTrue(verify.exists()) - Assert.assertEquals((1024 * 128).toLong(), verify.length()) + assertTrue(verify.exists()) + assertEquals((1024 * 128).toLong(), verify.length()) } }, ServiceWatcherUtil.UPDATE_POSITION, @@ -101,23 +100,25 @@ class MultipartRarExtractorTest { */ @Test fun testExtractMultiVolumeV5Rar() { - try { - RarExtractor( - ApplicationProvider.getApplicationContext(), - File( - Environment.getExternalStorageDirectory(), - "test-multipart-archive-v5.part1.rar", - ) - .absolutePath, - Environment.getExternalStorageDirectory().absolutePath, - callback, - ServiceWatcherUtil.UPDATE_POSITION, - ).extractEverything() - Assert.fail("No exception was thrown") - } catch (expected: IOException) { - expected.printStackTrace() - Assert.assertEquals(UnsupportedRarV5Exception::class.java, expected.cause!!.javaClass) - } + val latch = CountDownLatch(1) + RarExtractor( + ApplicationProvider.getApplicationContext(), + File( + Environment.getExternalStorageDirectory(), + "test-multipart-archive-v5.part1.rar", + ).absolutePath, + Environment.getExternalStorageDirectory().absolutePath, + object : OnUpdate by callback { + override fun onFinish() { + latch.countDown() + val verify = File(Environment.getExternalStorageDirectory(), "test.bin") + assertTrue(verify.exists()) + assertEquals((1024 * 128).toLong(), verify.length()) + } + }, + ServiceWatcherUtil.UPDATE_POSITION, + ).extractEverything() + latch.await() } private fun copyArchivesToStorage() { diff --git a/build.gradle b/build.gradle index 379e3c33b2..d24894a4b5 100644 --- a/build.gradle +++ b/build.gradle @@ -18,8 +18,8 @@ buildscript { } plugins { - id "com.diffplug.spotless" version "6.25.0" - id "com.google.devtools.ksp" version "1.9.25-1.0.20" apply false + id "com.diffplug.spotless" version "8.9.0" + id "com.google.devtools.ksp" version "2.2.20-2.0.4" apply false } allprojects { @@ -53,6 +53,7 @@ spotless { kotlin { licenseHeaderFile 'amaze.license.spotless.txt' target '*/src/**/*.kt' + targetExclude 'portscanner/src/**/*.kt' ktlint("1.1.1").setEditorConfigPath("$projectDir/.editorconfig") } } @@ -72,23 +73,25 @@ configurations { robo32 robo33 robo34 + robo35 } dependencies { - robo21 "org.robolectric:android-all-instrumented:5.0.2_r3-robolectric-r0-i4" - robo22 "org.robolectric:android-all-instrumented:5.1.1_r9-robolectric-r2-i4" - robo23 "org.robolectric:android-all-instrumented:6.0.1_r3-robolectric-r1-i4" - robo24 "org.robolectric:android-all-instrumented:7.0.0_r1-robolectric-r1-i4" - robo25 "org.robolectric:android-all-instrumented:7.1.0_r7-robolectric-r1-i4" - robo26 "org.robolectric:android-all-instrumented:8.0.0_r4-robolectric-r1-i4" - robo27 "org.robolectric:android-all-instrumented:8.1.0-robolectric-4611349-i4" - robo28 "org.robolectric:android-all-instrumented:9-robolectric-4913185-2-i4" - robo29 "org.robolectric:android-all-instrumented:10-robolectric-5803371-i4" - robo30 "org.robolectric:android-all-instrumented:11-robolectric-6757853-i4" - robo31 "org.robolectric:android-all-instrumented:12-robolectric-7732740-i4" - robo32 "org.robolectric:android-all-instrumented:12.1-robolectric-8229987-i4" - robo33 "org.robolectric:android-all-instrumented:13-robolectric-9030017-i4" - robo34 "org.robolectric:android-all-instrumented:14-robolectric-10818077-i4" + robo21 "org.robolectric:android-all-instrumented:5.0.2_r3-robolectric-r0-i7" + robo22 "org.robolectric:android-all-instrumented:5.1.1_r9-robolectric-r2-i7" + robo23 "org.robolectric:android-all-instrumented:6.0.1_r3-robolectric-r1-i7" + robo24 "org.robolectric:android-all-instrumented:7.0.0_r1-robolectric-r1-i7" + robo25 "org.robolectric:android-all-instrumented:7.1.0_r7-robolectric-r1-i7" + robo26 "org.robolectric:android-all-instrumented:8.0.0_r4-robolectric-r1-i7" + robo27 "org.robolectric:android-all-instrumented:8.1.0-robolectric-4611349-i7" + robo28 "org.robolectric:android-all-instrumented:9-robolectric-4913185-2-i7" + robo29 "org.robolectric:android-all-instrumented:10-robolectric-5803371-i7" + robo30 "org.robolectric:android-all-instrumented:11-robolectric-6757853-i7" + robo31 "org.robolectric:android-all-instrumented:12-robolectric-7732740-i7" + robo32 "org.robolectric:android-all-instrumented:12.1-robolectric-8229987-i7" + robo33 "org.robolectric:android-all-instrumented:13-robolectric-9030017-i7" + robo34 "org.robolectric:android-all-instrumented:14-robolectric-10818077-i7" + robo35 "org.robolectric:android-all-instrumented:15-robolectric-12650502-i7" } def robolectricDependencies = "${rootProject.layout.buildDirectory.get().asFile}/robolectric" @@ -108,6 +111,7 @@ tasks.register('fetchRobolectricDependencies', Copy) { from configurations.robo32 from configurations.robo33 from configurations.robo34 + from configurations.robo35 into robolectricDependencies } diff --git a/commons_compress_7z/build.gradle b/commons_compress_7z/build.gradle index 74d66012b3..5f597d1d1d 100644 --- a/commons_compress_7z/build.gradle +++ b/commons_compress_7z/build.gradle @@ -3,7 +3,7 @@ apply plugin: 'kotlin-android' android { namespace "com.amaze.filemanager.filesystem.compressed.sevenz" - compileSdk libs.versions.compileSdk.get().toInteger() + compileSdkVersion libs.versions.compileSdk.get().toInteger() defaultConfig { minSdkVersion libs.versions.minSdk.get().toInteger() @@ -19,8 +19,8 @@ android { } } compileOptions { - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 + sourceCompatibility JavaVersion.VERSION_21 + targetCompatibility JavaVersion.VERSION_21 } } diff --git a/commons_compress_7z/src/main/AndroidManifest.xml b/commons_compress_7z/src/main/AndroidManifest.xml index 29ba17970f..8072ee00db 100644 --- a/commons_compress_7z/src/main/AndroidManifest.xml +++ b/commons_compress_7z/src/main/AndroidManifest.xml @@ -1,2 +1,2 @@ - + + diff --git a/file_operations/build.gradle b/file_operations/build.gradle index 5400d64458..3c8f78aebc 100644 --- a/file_operations/build.gradle +++ b/file_operations/build.gradle @@ -5,7 +5,7 @@ apply plugin: 'org.mozilla.rust-android-gradle.rust-android' android { namespace "com.amaze.filemanager.fileoperations" - compileSdk libs.versions.compileSdk.get().toInteger() + compileSdkVersion libs.versions.compileSdk.get().toInteger() ndkVersion libs.versions.ndk.get() defaultConfig { @@ -31,8 +31,8 @@ android { } compileOptions { - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 + sourceCompatibility JavaVersion.VERSION_21 + targetCompatibility JavaVersion.VERSION_21 } testOptions { @@ -41,10 +41,6 @@ android { returnDefaultValues = true } } - - kotlinOptions { - jvmTarget = '17' - } } // Rust configuration @@ -61,7 +57,7 @@ cargo { } kotlin { - jvmToolchain(17) + jvmToolchain(21) } // Ensure Rust libraries are built before Android tasks diff --git a/file_operations/src/main/AndroidManifest.xml b/file_operations/src/main/AndroidManifest.xml index f71066fedd..568741e54f 100644 --- a/file_operations/src/main/AndroidManifest.xml +++ b/file_operations/src/main/AndroidManifest.xml @@ -1,2 +1,2 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index a7ce00a43f..f3a8496d45 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,6 +11,57 @@ # The setting is particularly useful for tweaking memory settings. android.enableJetifier=true android.useAndroidX=true +android.jetifier.ignorelist=org.bouncycastle:bcpkix-jdk18on, \ + org.bouncycastle:bcprov-jdk18on, \ + org.bouncycastle:bcutil-jdk18on, \ + org.robolectric:annotations, \ + org.robolectric:junit, \ + org.robolectric:nativeruntime, \ + org.robolectric:pluginapi, \ + org.robolectric:plugins-maven-dependency-resolver, \ + org.robolectric:resource, \ + org.robolectric:robolectric, \ + org.robolectric:sandbox, \ + org.robolectric:shadowapi, \ + org.robolectric:shadows-framework, \ + org.robolectric:shadows-httpclient, \ + org.robolectric:utils, \ + org.robolectric:utils-reflector, \ + org.slf4j:slf4j-api, \ + net.lingala.zip4j:zip4j, \ + org.tukaani:xz, \ + org.jsoup:jsoup, \ + org.hamcrest:hamcrest, \ + org.hamcrest:hamcrest-core, \ + org.hamcrest:hamcrest-library, \ + org.awaitility:awaitility, \ + org.mockito:mockito-core, \ + org.mockito:mockito-inline, \ + io.mockk:mockk, \ + eu.agno3.jcifs:jcifs-ng, \ + commons-codec:commons-codec, \ + commons-net:commons-net, \ + commons-io:commons-io, \ + commons-logging:commons-logging, \ + com.google.guava:guava, \ + com.google.guava:listenablefuture, \ + com.github.npgall:concurrent-trees, \ + com.hierynomus:sshj, \ + com.ibm.icu:icu4j, \ + com.google.code.gson:gson, \ + com.google.guava:guava, \ + com.google.guava:listenablefuture, \ + ch.qos.logback:logback-core, \ + ch.qos.logback:logback-classic, \ + com.almworks.sqlite4java:sqlite4java, \ + org.apache.ftpserver:ftpserver, \ + com.github.topjohnwu.libsu:core, \ + com.github.topjohnwu.libsu:io, \ + org.apache.mina:mina-core, \ + org.apache.sshd:sshd-core, \ + org.apache.sshd:sshd-scp, \ + org.apache.sshd:sshd-sftp, \ + junit:junit org.gradle.jvmargs=-Xmx4608M -XX:+UseParallelGC \ --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \ diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8968d58db7..16ee06a521 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,74 +1,75 @@ [versions] -compileSdk = "34" +compileSdk = "35" minSdk = "21" targetSdk = "35" -kotlin = "1.9.25" +kotlin = "2.2.20" ndk = "28.2.13676358" #r28c jacocoAndroid = "0.2.1" -gradle = "8.5.2" +gradle = "8.13.2" easylauncher = "6.1.0" legacySupportV13 = "1.0.0" -systembartint = "1.0.3" -robolectric = "4.9" -glide = "4.16.0" -sshj = "0.39.0" +systembartint = "1.0.4" +robolectric = "4.15" +glide = "5.0.5" +sshj = "0.40.0" jcifs = "2.1.10" eventbus = "3.3.1" fabSpeedDial = "3.3.0" room = "2.5.2" -bouncyCastle = "1.77" -awaitility = "3.1.6" -androidXCore = "1.7.0" +bouncyCastle = "1.85" +awaitility = "4.3.0" +androidXActivity = "1.7.2" +androidXCore = "1.16.0" androidMaterial = "1.5.0" # Upgrade to 1.5 requires targetSdk 31 -androidXFragment = "1.5.6" -androidXAppCompat = "1.6.1" -androidXAnnotation = "1.7.1" +androidXFragment = "1.8.9" +androidXAppCompat = "1.7.1" +androidXAnnotation = "1.10.0" androidXPref = "1.2.1" androidXPalette = "1.0.0" androidXCardView = "1.0.0" -androidXConstraintLayout = "1.1.3" +androidXConstraintLayout = "2.2.2" androidXBiometric = "1.1.0" -androidXTest = "1.6.1" -androidXTestRunner = "1.6.2" -androidXTestExt = "1.2.1" +androidXTest = "1.7.0" +androidXTestRunner = "1.7.0" +androidXTestExt = "1.3.0" androidXArchCoreTest = "2.2.0" androidXMultidex = "2.0.1" autoService = "1.1.1" -kotlinxCoroutineTest = "1.7.3" -kotlinStdlibJdk8 = "1.9.20" +kotlinxCoroutineTest = "1.11.0" +kotlinStdlibJdk8 = "2.2.10" uiAutomator = "2.3.0" junit = "4.13.2" -slf4j = "2.0.13" -apacheSshd = "1.7.0" -apacheMina = "2.0.16" -mockito = "4.11.0" -mockitoInline = "4.11.0" -mockitoKotlin = "4.1.0" +slf4j = "2.0.18" +apacheSshd = "2.19.0" +apacheMina = "2.2.9" +mockito = "5.23.0" +mockitoInline = "5.2.0" +mockitoKotlin = "6.3.0" androidBilling = "8.0.0" cloudrailSiAndroid = "2.22.4" -junrar = "7.4.0" +junrar = "8.1.0" vectordrawableAnimated = "1.2.0" -xz = "1.9" -zip4j = "2.6.4" -espresso = "3.6.1" +xz = "1.12" +zip4j = "2.11.6" +espresso = "3.7.0" materialDialogs = "0.9.6.0" jacoco = "0.8.11" commonsCompress = "1.22" libsu = "3.2.1" -mockk = "1.13.4" +mockk = "1.14.11" logbackAndroid = "3.0.0" -logbackClassic = "1.4.14" -commonsNet = "3.8.0" -ftpserver = "1.1.1" -jsoup = "1.16.1" -gson = "2.11.0" +logbackClassic = "1.6.1" +commonsNet = "3.13.0" +ftpserver = "1.2.1" +jsoup = "1.23.1" +gson = "2.14.0" rxAndroid = "2.1.1" -rxJava = "2.2.9" -okHttp = "4.12.0" -acraCore = "5.12.0" -leakcanaryAndroid = "2.7" +rxJava = "2.2.21" +okHttp = "5.1.0" +acraCore = "5.13.1" +leakcanaryAndroid = "2.14" mpAndroidChart = "v3.0.2" concurrentTrees = "2.6.1" aboutLibraries = "6.1.1" @@ -81,6 +82,7 @@ jacoco-android-plugin = { module = "com.mxalbert.gradle:jacoco-android", version kotlin-gradle-plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } rust-android-gradle = { module = "org.mozilla.rust-android-gradle.rust-android:org.mozilla.rust-android-gradle.rust-android.gradle.plugin", version.ref = "rustAndroidGradle" } +androidX-activity = { module = "androidx.activity:activity-ktx", version.ref = "androidXActivity" } androidX-appcompat = { module = "androidx.appcompat:appcompat", version.ref = "androidXAppCompat" } androidX-constraintLayout = { module = "androidx.constraintlayout:constraintlayout", version.ref = "androidXConstraintLayout" } androidX-core = { module = "androidx.core:core-ktx", version.ref = "androidXCore" } @@ -111,6 +113,8 @@ bcprov-jdk18on = { module = "org.bouncycastle:bcprov-jdk18on", version.ref = "bo apache-mina-core = { module = "org.apache.mina:mina-core", version.ref = "apacheMina" } apache-sshd = { module = "org.apache.sshd:sshd-core", version.ref = "apacheSshd" } +apache-sshd-scp = { module = "org.apache.sshd:sshd-scp", version.ref = "apacheSshd" } +apache-sshd-sftp = { module = "org.apache.sshd:sshd-sftp", version.ref = "apacheSshd" } apache-ftpserver-ftplet-api = { module = "org.apache.ftpserver:ftplet-api", version.ref = "ftpserver" } apache-ftpserver-core = { module = "org.apache.ftpserver:ftpserver-core", version.ref = "ftpserver" } diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 249e5832f090a2944b7473328c07c9755baa3196..1b33c55baabb587c669f562ae36f953de2481846 100644 GIT binary patch literal 43764 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 /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -114,7 +114,7 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar +CLASSPATH="\\\"\\\"" # Determine the Java command to use to start the JVM. @@ -133,22 +133,29 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -193,16 +200,20 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index f127cfd49d..db3a6ac207 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -26,6 +28,7 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -42,11 +45,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -56,22 +59,22 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar +set CLASSPATH= @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell diff --git a/portscanner/build.gradle b/portscanner/build.gradle index ee039f9b63..cc0718f0b6 100644 --- a/portscanner/build.gradle +++ b/portscanner/build.gradle @@ -5,11 +5,11 @@ apply plugin: 'kotlin-parcelize' android { namespace 'com.stealthcopter.networktools' - compileSdk libs.versions.compileSdk.get().toInteger() + compileSdkVersion libs.versions.compileSdk.get().toInteger() defaultConfig { - minSdk libs.versions.minSdk.get().toInteger() - targetSdk libs.versions.targetSdk.get().toInteger() + minSdkVersion libs.versions.minSdk.get().toInteger() + targetSdkVersion libs.versions.targetSdk.get().toInteger() testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" consumerProguardFiles "consumer-rules.pro" @@ -22,13 +22,13 @@ android { } } compileOptions { - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 + sourceCompatibility JavaVersion.VERSION_21 + targetCompatibility JavaVersion.VERSION_21 } } kotlin { - jvmToolchain(17) + jvmToolchain(21) } dependencies { diff --git a/testShared/src/test/java/com/amaze/filemanager/shadows/ShadowContentResolver.kt b/testShared/src/test/java/com/amaze/filemanager/shadows/ShadowContentResolver.kt deleted file mode 100644 index d037413740..0000000000 --- a/testShared/src/test/java/com/amaze/filemanager/shadows/ShadowContentResolver.kt +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2014-2022 Arpit Khurana , Vishal Nehra , - * Emmanuel Messulam, Raymond Lai and Contributors. - * - * This file is part of Amaze File Manager. - * - * Amaze File Manager is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.amaze.filemanager.shadows - -import android.content.ContentResolver -import android.net.Uri -import org.robolectric.annotation.Implementation -import org.robolectric.annotation.Implements -import org.robolectric.shadows.ShadowContentResolver -import java.io.OutputStream - -/** - * [ShadowContentResolver] implementation to include - * [ContentResolver.openOutputStream] with Uri and open mode arguments. - * - * @see ContentResolver.openOutputStream(uri, String) - */ -@Implements(ContentResolver::class) -class ShadowContentResolver : ShadowContentResolver() { - /** - * Implements [ContentResolver.openOutputStream] with open mode parameter. - * - * Simply delegate to one without open mode. - */ - @Implementation - fun openOutputStream( - uri: Uri, - mode: String, - ): OutputStream? = super.openOutputStream(uri) -} diff --git a/testShared/src/test/java/com/amaze/filemanager/shadows/ShadowFileUtils.kt b/testShared/src/test/java/com/amaze/filemanager/shadows/ShadowFileUtils.kt index 31e7e499e9..783c481f6a 100644 --- a/testShared/src/test/java/com/amaze/filemanager/shadows/ShadowFileUtils.kt +++ b/testShared/src/test/java/com/amaze/filemanager/shadows/ShadowFileUtils.kt @@ -1,7 +1,6 @@ /* * Copyright (C) 2014-2024 Arpit Khurana , Vishal Nehra , - * Emmanuel Messulam, Raymond Lai , - * Vishnu Sanal and Contributors. + * Emmanuel Messulam, Raymond Lai and Contributors. * * This file is part of Amaze File Manager. * From c546b8e7ca8d30823f3c3a2c84b5581668eee3c5 Mon Sep 17 00:00:00 2001 From: TranceLove Date: Mon, 10 Aug 2026 18:02:30 +0900 Subject: [PATCH 2/8] Enable JVM tooling discovery Also add bytebuddy to jetifier ignore list --- gradle.properties | 2 ++ gradle/gradle-daemon-jvm.properties | 12 ++++++++++++ settings.gradle | 3 +++ 3 files changed, 17 insertions(+) create mode 100644 gradle/gradle-daemon-jvm.properties diff --git a/gradle.properties b/gradle.properties index f3a8496d45..3179809355 100644 --- a/gradle.properties +++ b/gradle.properties @@ -61,6 +61,8 @@ android.jetifier.ignorelist=org.bouncycastle:bcpkix-jdk18on, \ org.apache.sshd:sshd-core, \ org.apache.sshd:sshd-scp, \ org.apache.sshd:sshd-sftp, \ + net.bytebuddy:byte-buddy, \ + net.bytebuddy:byte-buddy-agent, \ junit:junit org.gradle.jvmargs=-Xmx4608M -XX:+UseParallelGC \ diff --git a/gradle/gradle-daemon-jvm.properties b/gradle/gradle-daemon-jvm.properties new file mode 100644 index 0000000000..5c2ece29a4 --- /dev/null +++ b/gradle/gradle-daemon-jvm.properties @@ -0,0 +1,12 @@ +#This file is generated by updateDaemonJvm +toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/b43b10bd60d8689faca2651e270e52e7/redirect +toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/5307a953ce47831ecf5a715128766856/redirect +toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/b43b10bd60d8689faca2651e270e52e7/redirect +toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/5307a953ce47831ecf5a715128766856/redirect +toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/03ffe42aae843e3c5ed7cf8ae3ae9a73/redirect +toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/6ec5bdd39b6256778a046b2b37f8de26/redirect +toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/b43b10bd60d8689faca2651e270e52e7/redirect +toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/5307a953ce47831ecf5a715128766856/redirect +toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/6fb5075b2dcb0e97607e0bbd93459403/redirect +toolchainVendor=AMAZON +toolchainVersion=21 diff --git a/settings.gradle b/settings.gradle index 70edc43f9d..0023200c52 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,3 +1,6 @@ +plugins { + id 'org.gradle.toolchains.foojay-resolver-convention' version '1.0.0' +} include ':file_operations' include ':portscanner' include ':app', ':commons_compress_7z' From d6d4f56f952032ecc9ed0addd26bd774f7811673 Mon Sep 17 00:00:00 2001 From: TranceLove Date: Mon, 10 Aug 2026 18:04:40 +0900 Subject: [PATCH 3/8] Increase Robolectric tests minimum SDK to 23 For preparation to Robolectric 4.16 --- .../asynctasks/movecopy/PreparePasteTask.kt | 79 +++++++++++-------- .../application/AppConfigTest.java | 4 +- .../asynctasks/AbstractDeleteTaskTestBase.kt | 4 +- .../asynctasks/DbViewerTaskTest.java | 4 +- .../AbstractCompressedHelperCallableTest.kt | 4 +- .../CompressedHelperForBadArchiveTest.kt | 4 +- .../SearchResultListSorterTest.kt | 2 +- .../ssh/PemToKeyPairObservableEd25519Test.kt | 4 +- .../ssh/PemToKeyPairObservableRsaTest.kt | 4 +- .../ssh/SshAuthenticationTaskTest.kt | 4 +- .../read/ReadTextFileCallableTest.kt | 4 +- .../write/WriteTextFileCallableTest.java | 4 +- .../services/DecryptServiceTest.kt | 3 +- .../services/EncryptServiceTest.kt | 12 ++- .../services/ExtractServiceTest.kt | 2 +- ...ServiceAndroidFileSystemIntegrationTest.kt | 4 +- .../asynchronous/services/ZipServiceTest.kt | 4 +- .../services/ftp/FtpReceiverTest.kt | 4 +- .../database/ExplorerDatabaseMigrationTest.kt | 4 +- .../UtilitiesDatabaseMigrationTest.kt | 4 +- .../filemanager/database/UtilsHandlerTest.kt | 4 +- .../EncryptedStringTypeConverterTest.kt | 4 +- ...bstractFilenameHelperIncrementNameTests.kt | 4 +- .../filesystem/AbstractOperationsTestBase.kt | 4 +- .../EditableFileAbstractionTest.java | 4 +- .../filemanager/filesystem/HybridFileTest.kt | 4 +- .../filesystem/OperationsTest.java | 4 +- .../filesystem/RootHelperTest.java | 4 +- .../filesystem/compressed/B0rkenZipTest.java | 4 +- .../compressed/CompressedHelperTest.java | 4 +- .../extractcontents/AbstractExtractorTest.kt | 4 +- .../filesystem/files/FileListSorterTest.kt | 2 +- .../filesystem/files/FileUtilsTest.kt | 4 +- .../filesystem/files/sort/DirSortByTest.kt | 2 +- .../filesystem/files/sort/SortByTest.kt | 2 +- .../filesystem/files/sort/SortTypeTest.kt | 2 +- .../ftp/NetCopyClientConnectionPoolFtpTest.kt | 4 +- .../commands/AbstractFtpserverCommandTest.kt | 4 +- .../filesystem/root/ListFilesCommandTest.kt | 4 +- .../filesystem/root/ListFilesCommandTest2.kt | 4 +- .../filesystem/smb/CifsContextsTest.java | 4 +- .../filesystem/smb/SmbHybridFileTest.kt | 4 +- .../filesystem/ssh/AbstractSftpServerTest.kt | 4 +- .../ssh/NetCopyClientConnectionPoolSshTest.kt | 4 +- .../filesystem/ssh/SshHybridFileTest.kt | 4 +- .../AbstractMainActivityTestBase.kt | 4 +- .../activities/DatabaseViewerActivityTest.kt | 4 +- .../ui/activities/PermissionsActivityTest.kt | 4 +- .../ui/activities/TextEditorActivityTest.java | 4 +- .../ui/dialogs/AbstractEncryptDialogTests.kt | 14 +++- .../ui/dialogs/ColorPickerDialogTest.kt | 4 +- .../dialogs/DecryptFingerprintDialogTest.kt | 5 +- .../ui/fragments/CloudSheetFragmentTest.java | 4 +- .../UiPrefsFragmentTest.kt | 2 +- .../amaze/filemanager/ui/icons/IconsTest.java | 8 +- .../NotificationConstantsTest.java | 12 +-- .../filemanager/ui/theme/AppThemeTest.kt | 4 +- .../views/WarnableTextInputValidatorTest.java | 4 +- .../amaze/filemanager/utils/AESCryptTest.kt | 4 +- .../filemanager/utils/AnimUtilsTest.java | 4 +- .../amaze/filemanager/utils/CryptUtilTest.kt | 4 +- .../utils/MinMaxInputFilterTest.kt | 4 +- .../filemanager/utils/NetworkUtilTest.kt | 4 +- .../amaze/filemanager/utils/SmbUtilTest.kt | 4 +- .../amaze/filemanager/utils/TinyDBTest.java | 4 +- .../amaze/filemanager/utils/UtilsTest.java | 4 +- .../utils/X509CertificateUtilTest.kt | 4 +- ...tractSubnetDiscoverDevicesStrategyTests.kt | 4 +- .../MultipartRarExtractorTest.kt | 2 +- build.gradle | 31 ++++---- .../test/ShadowPasswordUtilTest.java | 4 +- 71 files changed, 208 insertions(+), 192 deletions(-) mode change 100644 => 100755 app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/movecopy/PreparePasteTask.kt diff --git a/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/movecopy/PreparePasteTask.kt b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/movecopy/PreparePasteTask.kt old mode 100644 new mode 100755 index 7ee9cb13cb..7c37a24b8a --- a/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/movecopy/PreparePasteTask.kt +++ b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/movecopy/PreparePasteTask.kt @@ -21,7 +21,6 @@ package com.amaze.filemanager.asynchronous.asynctasks.movecopy import android.app.ProgressDialog -import android.content.Context import android.content.Intent import android.view.LayoutInflater import android.widget.Toast @@ -133,44 +132,54 @@ class PreparePasteTask(strongRefMain: MainActivity) { return } - val totalBytes = FileUtils.getTotalBytes(filesToCopy, context.get()) - destination = HybridFile(openMode, targetPath) - destination.generateMode(context.get()) + coroutineScope.launch { + val contextRef = context.get() ?: return@launch + val totalBytes = withContext(Dispatchers.IO) { FileUtils.getTotalBytes(filesToCopy, contextRef) } + destination = + withContext(Dispatchers.IO) { + HybridFile(openMode, targetPath).apply { generateMode(contextRef) } + } - if (filesToCopy.isNotEmpty() && - isMove && - filesToCopy[0].getParent(context.get()) == targetPath - ) { - Toast.makeText(context.get(), R.string.same_dir_move_error, Toast.LENGTH_SHORT).show() - MediaConnectionUtils.scanFile(context.get() as Context, filesToCopy.toTypedArray()) - return - } + if (filesToCopy.isNotEmpty() && + isMove && + filesToCopy[0].getParent(contextRef) == targetPath + ) { + withContext(Dispatchers.Main) { + Toast.makeText(contextRef, R.string.same_dir_move_error, Toast.LENGTH_SHORT).show() + } + MediaConnectionUtils.scanFile(contextRef, filesToCopy.toTypedArray()) + return@launch + } - val isMoveSupported = - isMove && - destination.mode == openMode && - MoveFiles.getOperationSupportedFileSystem().contains(openMode) + val isMoveSupported = + isMove && + destination.mode == openMode && + MoveFiles.getOperationSupportedFileSystem().contains(openMode) - if (destination.usableSpace < totalBytes && - !isMoveSupported - ) { - Toast.makeText(context.get(), R.string.in_safe, Toast.LENGTH_SHORT).show() - return - } - @Suppress("DEPRECATION") - progressDialog = - ProgressDialog.show( - context.get(), - "", - context.get()?.getString(R.string.checking_conflicts), + if (destination.usableSpace < totalBytes && !isMoveSupported) { + withContext(Dispatchers.Main) { + Toast.makeText(contextRef, R.string.in_safe, Toast.LENGTH_SHORT).show() + } + return@launch + } + + withContext(Dispatchers.Main) { + @Suppress("DEPRECATION") + progressDialog = + ProgressDialog.show( + contextRef, + "", + contextRef.getString(R.string.checking_conflicts), + ) + } + checkConflicts( + isRootMode, + filesToCopy, + destination, + conflictingFiles, + conflictingDirActionMap, ) - checkConflicts( - isRootMode, - filesToCopy, - destination, - conflictingFiles, - conflictingDirActionMap, - ) + } } private fun checkConflicts( diff --git a/app/src/test/java/com/amaze/filemanager/application/AppConfigTest.java b/app/src/test/java/com/amaze/filemanager/application/AppConfigTest.java index de57e3ea1b..cd623875ca 100644 --- a/app/src/test/java/com/amaze/filemanager/application/AppConfigTest.java +++ b/app/src/test/java/com/amaze/filemanager/application/AppConfigTest.java @@ -20,7 +20,7 @@ package com.amaze.filemanager.application; -import static android.os.Build.VERSION_CODES.LOLLIPOP; +import static android.os.Build.VERSION_CODES.M; import static android.os.Build.VERSION_CODES.P; import static android.os.Looper.getMainLooper; import static org.awaitility.Awaitility.await; @@ -51,7 +51,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; @RunWith(AndroidJUnit4.class) -@Config(sdk = {LOLLIPOP, P, Build.VERSION_CODES.R}) +@Config(sdk = {M, P, Build.VERSION_CODES.R}) public class AppConfigTest { @After diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/AbstractDeleteTaskTestBase.kt b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/AbstractDeleteTaskTestBase.kt index c77388920d..4dcdf74ffc 100644 --- a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/AbstractDeleteTaskTestBase.kt +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/AbstractDeleteTaskTestBase.kt @@ -23,7 +23,7 @@ package com.amaze.filemanager.asynchronous.asynctasks import android.Manifest import android.content.Context import android.os.Build -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import android.os.Looper import android.os.storage.StorageManager @@ -70,7 +70,7 @@ import org.robolectric.shadows.ShadowToast ShadowFileUtils::class, ShadowPasswordUtil::class, ], - sdk = [LOLLIPOP, P, Build.VERSION_CODES.R], + sdk = [M, P, Build.VERSION_CODES.R], ) abstract class AbstractDeleteTaskTestBase { private var ctx: Context? = null diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/DbViewerTaskTest.java b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/DbViewerTaskTest.java index 343e16b743..eb80992910 100644 --- a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/DbViewerTaskTest.java +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/DbViewerTaskTest.java @@ -20,7 +20,7 @@ package com.amaze.filemanager.asynchronous.asynctasks; -import static android.os.Build.VERSION_CODES.LOLLIPOP; +import static android.os.Build.VERSION_CODES.M; import static android.os.Build.VERSION_CODES.P; import static android.os.Looper.getMainLooper; import static android.view.View.VISIBLE; @@ -58,7 +58,7 @@ @RunWith(AndroidJUnit4.class) @Config( shadows = {ShadowMultiDex.class}, - sdk = {LOLLIPOP, P, Build.VERSION_CODES.R}) + sdk = {M, P, Build.VERSION_CODES.R}) public class DbViewerTaskTest { private WebView webView; diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/AbstractCompressedHelperCallableTest.kt b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/AbstractCompressedHelperCallableTest.kt index ca6c8959f5..ef9b835b92 100644 --- a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/AbstractCompressedHelperCallableTest.kt +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/AbstractCompressedHelperCallableTest.kt @@ -21,7 +21,7 @@ package com.amaze.filemanager.asynchronous.asynctasks.compress import android.os.Build -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import android.os.Environment import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -37,7 +37,7 @@ import java.io.FileOutputStream import java.util.TimeZone @RunWith(AndroidJUnit4::class) -@Config(shadows = [ShadowMultiDex::class], sdk = [LOLLIPOP, P, Build.VERSION_CODES.R]) +@Config(shadows = [ShadowMultiDex::class], sdk = [M, P, Build.VERSION_CODES.R]) abstract class AbstractCompressedHelperCallableTest { private lateinit var systemTz: TimeZone diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/CompressedHelperForBadArchiveTest.kt b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/CompressedHelperForBadArchiveTest.kt index 335f975c18..41db09d4eb 100644 --- a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/CompressedHelperForBadArchiveTest.kt +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/compress/CompressedHelperForBadArchiveTest.kt @@ -20,7 +20,7 @@ package com.amaze.filemanager.asynchronous.asynctasks.compress -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import android.os.Environment import androidx.test.core.app.ApplicationProvider @@ -42,7 +42,7 @@ import java.io.FileOutputStream * Test behaviour of CompressedHelpers in handling corrupt archives. */ @RunWith(AndroidJUnit4::class) -@Config(shadows = [ShadowMultiDex::class], sdk = [LOLLIPOP, P]) +@Config(shadows = [ShadowMultiDex::class], sdk = [M, P]) class CompressedHelperForBadArchiveTest { /** * Test handling of corrupt archive with random junk. diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/searchfilesystem/SearchResultListSorterTest.kt b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/searchfilesystem/SearchResultListSorterTest.kt index 097eeb34fd..ef65130190 100644 --- a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/searchfilesystem/SearchResultListSorterTest.kt +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/searchfilesystem/SearchResultListSorterTest.kt @@ -41,7 +41,7 @@ import java.util.regex.Pattern @RunWith(AndroidJUnit4::class) @Config( shadows = [ShadowMultiDex::class], - sdk = [Build.VERSION_CODES.LOLLIPOP, Build.VERSION_CODES.P, Build.VERSION_CODES.R], + sdk = [Build.VERSION_CODES.M, Build.VERSION_CODES.P, Build.VERSION_CODES.R], ) @Suppress("StringLiteralDuplication", "ComplexMethod", "LongMethod", "LargeClass") class SearchResultListSorterTest { diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/ssh/PemToKeyPairObservableEd25519Test.kt b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/ssh/PemToKeyPairObservableEd25519Test.kt index 1cfc834af1..75586a506f 100644 --- a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/ssh/PemToKeyPairObservableEd25519Test.kt +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/ssh/PemToKeyPairObservableEd25519Test.kt @@ -21,7 +21,7 @@ package com.amaze.filemanager.asynchronous.asynctasks.ssh import android.os.Build.VERSION_CODES -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import androidx.test.ext.junit.runners.AndroidJUnit4 import com.amaze.filemanager.shadows.ShadowFileUtils @@ -45,7 +45,7 @@ import org.robolectric.annotation.Config @RunWith(AndroidJUnit4::class) @Config( shadows = [ShadowMultiDex::class, ShadowTabHandler::class, ShadowFileUtils::class], - sdk = [LOLLIPOP, P, VERSION_CODES.R], + sdk = [M, P, VERSION_CODES.R], ) class PemToKeyPairObservableEd25519Test { companion object { diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/ssh/PemToKeyPairObservableRsaTest.kt b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/ssh/PemToKeyPairObservableRsaTest.kt index 3590c52573..62d8e693cf 100644 --- a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/ssh/PemToKeyPairObservableRsaTest.kt +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/ssh/PemToKeyPairObservableRsaTest.kt @@ -22,7 +22,7 @@ package com.amaze.filemanager.asynchronous.asynctasks.ssh import android.os.Build.VERSION.SDK_INT import android.os.Build.VERSION_CODES -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.N import android.os.Build.VERSION_CODES.P import androidx.appcompat.widget.AppCompatEditText @@ -65,7 +65,7 @@ import java.util.concurrent.TimeUnit @RunWith(AndroidJUnit4::class) @Config( shadows = [ShadowMultiDex::class, ShadowTabHandler::class, ShadowFileUtils::class], - sdk = [LOLLIPOP, P, VERSION_CODES.R], + sdk = [M, P, VERSION_CODES.R], ) class PemToKeyPairObservableRsaTest { companion object { diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/ssh/SshAuthenticationTaskTest.kt b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/ssh/SshAuthenticationTaskTest.kt index a176c0fdd6..a9f8a5e33d 100644 --- a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/ssh/SshAuthenticationTaskTest.kt +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/ssh/SshAuthenticationTaskTest.kt @@ -22,7 +22,7 @@ package com.amaze.filemanager.asynchronous.asynctasks.ssh import android.content.Context import android.os.Build -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -66,7 +66,7 @@ import java.util.concurrent.CountDownLatch @RunWith(AndroidJUnit4::class) @Config( shadows = [ShadowMultiDex::class, ShadowPasswordUtil::class], - sdk = [LOLLIPOP, P, Build.VERSION_CODES.R], + sdk = [M, P, Build.VERSION_CODES.R], ) @Suppress("StringLiteralDuplication") class SshAuthenticationTaskTest { diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/texteditor/read/ReadTextFileCallableTest.kt b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/texteditor/read/ReadTextFileCallableTest.kt index f120e7f542..ed1c35d76d 100644 --- a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/texteditor/read/ReadTextFileCallableTest.kt +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/texteditor/read/ReadTextFileCallableTest.kt @@ -23,7 +23,7 @@ package com.amaze.filemanager.asynchronous.asynctasks.texteditor.read import android.content.Context import android.net.Uri import android.os.Build -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -46,7 +46,7 @@ import kotlin.random.Random @RunWith(AndroidJUnit4::class) @Config( shadows = [ShadowMultiDex::class], - sdk = [LOLLIPOP, P, Build.VERSION_CODES.R], + sdk = [M, P, Build.VERSION_CODES.R], ) class ReadTextFileCallableTest { /** diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/texteditor/write/WriteTextFileCallableTest.java b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/texteditor/write/WriteTextFileCallableTest.java index 156314e0cd..3c9ecf41c5 100644 --- a/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/texteditor/write/WriteTextFileCallableTest.java +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/asynctasks/texteditor/write/WriteTextFileCallableTest.java @@ -20,7 +20,7 @@ package com.amaze.filemanager.asynchronous.asynctasks.texteditor.write; -import static android.os.Build.VERSION_CODES.LOLLIPOP; +import static android.os.Build.VERSION_CODES.M; import static android.os.Build.VERSION_CODES.P; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; @@ -65,7 +65,7 @@ @RunWith(AndroidJUnit4.class) @Config( shadows = {ShadowMultiDex.class, ShadowContentResolver.class}, - sdk = {LOLLIPOP, P, Build.VERSION_CODES.R}) + sdk = {M, P, Build.VERSION_CODES.R}) public class WriteTextFileCallableTest { private static final String contents = "This is modified data"; diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/services/DecryptServiceTest.kt b/app/src/test/java/com/amaze/filemanager/asynchronous/services/DecryptServiceTest.kt index eca0bf4fd4..302af8d7af 100644 --- a/app/src/test/java/com/amaze/filemanager/asynchronous/services/DecryptServiceTest.kt +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/services/DecryptServiceTest.kt @@ -25,7 +25,6 @@ import android.content.Context import android.content.Intent import android.os.Build import android.os.Build.VERSION.SDK_INT -import android.os.Build.VERSION_CODES.LOLLIPOP import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import android.os.Environment @@ -64,7 +63,7 @@ import java.util.concurrent.TimeUnit import kotlin.random.Random @RunWith(AndroidJUnit4::class) -@Config(shadows = [ShadowMultiDex::class], sdk = [LOLLIPOP, P, Build.VERSION_CODES.R]) +@Config(shadows = [ShadowMultiDex::class], sdk = [M, P, Build.VERSION_CODES.R]) @Suppress("StringLiteralDuplication") class DecryptServiceTest { private lateinit var source: ByteArray diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/services/EncryptServiceTest.kt b/app/src/test/java/com/amaze/filemanager/asynchronous/services/EncryptServiceTest.kt index 7443d72e6d..5c2dc3bac1 100644 --- a/app/src/test/java/com/amaze/filemanager/asynchronous/services/EncryptServiceTest.kt +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/services/EncryptServiceTest.kt @@ -25,8 +25,8 @@ import android.content.Context import android.content.Intent import android.os.Build import android.os.Build.VERSION.SDK_INT -import android.os.Build.VERSION_CODES.LOLLIPOP import android.os.Build.VERSION_CODES.M +import android.os.Build.VERSION_CODES.O import android.os.Build.VERSION_CODES.P import android.os.Environment import android.util.Log @@ -68,7 +68,7 @@ import java.util.concurrent.TimeUnit import kotlin.random.Random @RunWith(AndroidJUnit4::class) -@Config(shadows = [ShadowMultiDex::class], sdk = [LOLLIPOP, P, Build.VERSION_CODES.R]) +@Config(shadows = [ShadowMultiDex::class], sdk = [M, P, Build.VERSION_CODES.R]) class EncryptServiceTest { private lateinit var service: EncryptService private lateinit var notificationManager: ShadowNotificationManager @@ -128,7 +128,9 @@ class EncryptServiceTest { assertTrue(notificationManager.activeNotifications.isNotEmpty()) notificationManager.activeNotifications.first().let { assertEquals(NotificationConstants.ENCRYPT_ID, it.id) - assertEquals(NotificationConstants.CHANNEL_NORMAL_ID, it.notification.channelId) + if (SDK_INT >= O) { + assertEquals(NotificationConstants.CHANNEL_NORMAL_ID, it.notification.channelId) + } } await().atMost(10, TimeUnit.SECONDS).until { targetFile.length() > 0 && notificationManager.activeNotifications.isEmpty() @@ -171,7 +173,9 @@ class EncryptServiceTest { assertTrue(notificationManager.activeNotifications.isNotEmpty()) notificationManager.activeNotifications.first().let { assertEquals(NotificationConstants.ENCRYPT_ID, it.id) - assertEquals(NotificationConstants.CHANNEL_NORMAL_ID, it.notification.channelId) + if (SDK_INT >= O) { + assertEquals(NotificationConstants.CHANNEL_NORMAL_ID, it.notification.channelId) + } } await().atMost(10, TimeUnit.SECONDS).until { targetFile.length() > 0 && notificationManager.activeNotifications.isEmpty() diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/services/ExtractServiceTest.kt b/app/src/test/java/com/amaze/filemanager/asynchronous/services/ExtractServiceTest.kt index 94259d4102..0f843504bd 100644 --- a/app/src/test/java/com/amaze/filemanager/asynchronous/services/ExtractServiceTest.kt +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/services/ExtractServiceTest.kt @@ -114,7 +114,7 @@ class ExtractServiceTest { @Rule @JvmField @RequiresApi(VERSION_CODES.R) - val allFilesPermissionRule = + val allFilesPermissionRule: GrantPermissionRule = GrantPermissionRule .grant(Manifest.permission.MANAGE_EXTERNAL_STORAGE) diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/services/FtpServiceAndroidFileSystemIntegrationTest.kt b/app/src/test/java/com/amaze/filemanager/asynchronous/services/FtpServiceAndroidFileSystemIntegrationTest.kt index 3dbfc48c0d..ec613dff73 100644 --- a/app/src/test/java/com/amaze/filemanager/asynchronous/services/FtpServiceAndroidFileSystemIntegrationTest.kt +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/services/FtpServiceAndroidFileSystemIntegrationTest.kt @@ -26,7 +26,7 @@ import android.net.NetworkInfo import android.net.Uri import android.net.wifi.WifiInfo import android.net.wifi.WifiManager -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Environment import androidx.preference.PreferenceManager import androidx.test.core.app.ApplicationProvider @@ -64,7 +64,7 @@ import kotlin.random.Random @Ignore("Pending fix for testing against newer Androids") @RunWith(AndroidJUnit4::class) -@Config(sdk = [LOLLIPOP], shadows = [ShadowMultiDex::class]) +@Config(sdk = [M], shadows = [ShadowMultiDex::class]) @LooperMode(LooperMode.Mode.PAUSED) @Suppress("StringLiteralDuplication") class FtpServiceAndroidFileSystemIntegrationTest { diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/services/ZipServiceTest.kt b/app/src/test/java/com/amaze/filemanager/asynchronous/services/ZipServiceTest.kt index 9faa8029cf..768f2e220a 100644 --- a/app/src/test/java/com/amaze/filemanager/asynchronous/services/ZipServiceTest.kt +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/services/ZipServiceTest.kt @@ -23,7 +23,7 @@ package com.amaze.filemanager.asynchronous.services import android.content.Context import android.content.Intent import android.os.Build -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import android.os.Looper.getMainLooper import androidx.test.core.app.ApplicationProvider @@ -59,7 +59,7 @@ import kotlin.random.Random @RunWith(RobolectricTestRunner::class) @LooperMode(LooperMode.Mode.PAUSED) -@Config(shadows = [ShadowMultiDex::class], sdk = [LOLLIPOP, P, Build.VERSION_CODES.R]) +@Config(shadows = [ShadowMultiDex::class], sdk = [M, P, Build.VERSION_CODES.R]) class ZipServiceTest { val dt = DateTimeFormatter.ofPattern("yyyyMMddkkmm") val dates = diff --git a/app/src/test/java/com/amaze/filemanager/asynchronous/services/ftp/FtpReceiverTest.kt b/app/src/test/java/com/amaze/filemanager/asynchronous/services/ftp/FtpReceiverTest.kt index 02d132b982..7b0a5dbb7d 100644 --- a/app/src/test/java/com/amaze/filemanager/asynchronous/services/ftp/FtpReceiverTest.kt +++ b/app/src/test/java/com/amaze/filemanager/asynchronous/services/ftp/FtpReceiverTest.kt @@ -22,7 +22,7 @@ package com.amaze.filemanager.asynchronous.services.ftp import android.content.Intent import android.os.Build -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.N import android.os.Build.VERSION_CODES.O import android.os.Build.VERSION_CODES.P @@ -43,7 +43,7 @@ import org.junit.runner.RunWith import org.robolectric.annotation.Config @RunWith(AndroidJUnit4::class) -@Config(shadows = [ShadowMultiDex::class], sdk = [LOLLIPOP, P, Build.VERSION_CODES.R]) +@Config(shadows = [ShadowMultiDex::class], sdk = [M, P, Build.VERSION_CODES.R]) @Suppress("StringLiteralDuplication") class FtpReceiverTest { private lateinit var receiver: FtpReceiver diff --git a/app/src/test/java/com/amaze/filemanager/database/ExplorerDatabaseMigrationTest.kt b/app/src/test/java/com/amaze/filemanager/database/ExplorerDatabaseMigrationTest.kt index 69c1e48289..df15a90475 100644 --- a/app/src/test/java/com/amaze/filemanager/database/ExplorerDatabaseMigrationTest.kt +++ b/app/src/test/java/com/amaze/filemanager/database/ExplorerDatabaseMigrationTest.kt @@ -21,7 +21,7 @@ package com.amaze.filemanager.database import android.os.Build -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import androidx.room.Room import androidx.sqlite.db.framework.FrameworkSQLiteOpenHelperFactory @@ -44,7 +44,7 @@ import java.io.IOException @RunWith(AndroidJUnit4::class) @Config( shadows = [ShadowMultiDex::class, ShadowPasswordUtil::class], - sdk = [LOLLIPOP, P, Build.VERSION_CODES.R], + sdk = [M, P, Build.VERSION_CODES.R], ) @Suppress("StringLiteralDuplication", "ComplexMethod", "LongMethod") class ExplorerDatabaseMigrationTest { diff --git a/app/src/test/java/com/amaze/filemanager/database/UtilitiesDatabaseMigrationTest.kt b/app/src/test/java/com/amaze/filemanager/database/UtilitiesDatabaseMigrationTest.kt index f3167fcaf0..9bc04a4f09 100644 --- a/app/src/test/java/com/amaze/filemanager/database/UtilitiesDatabaseMigrationTest.kt +++ b/app/src/test/java/com/amaze/filemanager/database/UtilitiesDatabaseMigrationTest.kt @@ -21,7 +21,7 @@ package com.amaze.filemanager.database import android.os.Build -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import android.util.Base64 import androidx.room.Room @@ -52,7 +52,7 @@ import org.robolectric.annotation.Config @RunWith(AndroidJUnit4::class) @Config( shadows = [ShadowMultiDex::class, ShadowPasswordUtil::class], - sdk = [LOLLIPOP, P, Build.VERSION_CODES.R], + sdk = [M, P, Build.VERSION_CODES.R], ) class UtilitiesDatabaseMigrationTest { companion object { diff --git a/app/src/test/java/com/amaze/filemanager/database/UtilsHandlerTest.kt b/app/src/test/java/com/amaze/filemanager/database/UtilsHandlerTest.kt index 7b8a5e433c..64311aeb44 100644 --- a/app/src/test/java/com/amaze/filemanager/database/UtilsHandlerTest.kt +++ b/app/src/test/java/com/amaze/filemanager/database/UtilsHandlerTest.kt @@ -21,7 +21,7 @@ package com.amaze.filemanager.database import android.os.Build -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import android.os.Environment import android.os.Environment.DIRECTORY_DCIM @@ -53,7 +53,7 @@ import java.io.File @RunWith(AndroidJUnit4::class) @Config( shadows = [ShadowMultiDex::class, ShadowPasswordUtil::class], - sdk = [LOLLIPOP, P, Build.VERSION_CODES.R], + sdk = [M, P, Build.VERSION_CODES.R], ) class UtilsHandlerTest { companion object { diff --git a/app/src/test/java/com/amaze/filemanager/database/typeconverters/EncryptedStringTypeConverterTest.kt b/app/src/test/java/com/amaze/filemanager/database/typeconverters/EncryptedStringTypeConverterTest.kt index f5adf4c7bd..4e1aefedff 100644 --- a/app/src/test/java/com/amaze/filemanager/database/typeconverters/EncryptedStringTypeConverterTest.kt +++ b/app/src/test/java/com/amaze/filemanager/database/typeconverters/EncryptedStringTypeConverterTest.kt @@ -21,7 +21,7 @@ package com.amaze.filemanager.database.typeconverters import android.os.Build -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import androidx.test.ext.junit.runners.AndroidJUnit4 import com.amaze.filemanager.database.models.StringWrapper @@ -38,7 +38,7 @@ import org.robolectric.annotation.Config @RunWith(AndroidJUnit4::class) @Config( shadows = [ShadowMultiDex::class, ShadowPasswordUtil::class], - sdk = [LOLLIPOP, P, Build.VERSION_CODES.R], + sdk = [M, P, Build.VERSION_CODES.R], ) class EncryptedStringTypeConverterTest { /** diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/AbstractFilenameHelperIncrementNameTests.kt b/app/src/test/java/com/amaze/filemanager/filesystem/AbstractFilenameHelperIncrementNameTests.kt index f306e23d7a..e10cfbc453 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/AbstractFilenameHelperIncrementNameTests.kt +++ b/app/src/test/java/com/amaze/filemanager/filesystem/AbstractFilenameHelperIncrementNameTests.kt @@ -21,7 +21,7 @@ package com.amaze.filemanager.filesystem import android.os.Build -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import androidx.test.ext.junit.runners.AndroidJUnit4 import com.amaze.filemanager.application.AppConfig @@ -42,7 +42,7 @@ import org.robolectric.annotation.Config @RunWith(AndroidJUnit4::class) @Config( shadows = [ShadowMultiDex::class], - sdk = [LOLLIPOP, P, Build.VERSION_CODES.R], + sdk = [M, P, Build.VERSION_CODES.R], ) @Suppress("StringLiteralDuplication") abstract class AbstractFilenameHelperIncrementNameTests { diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/AbstractOperationsTestBase.kt b/app/src/test/java/com/amaze/filemanager/filesystem/AbstractOperationsTestBase.kt index 1aafbc6a79..75af7b7746 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/AbstractOperationsTestBase.kt +++ b/app/src/test/java/com/amaze/filemanager/filesystem/AbstractOperationsTestBase.kt @@ -23,7 +23,7 @@ package com.amaze.filemanager.filesystem import android.Manifest import android.content.Context import android.os.Build -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import android.os.Looper import android.os.storage.StorageManager @@ -68,7 +68,7 @@ import org.robolectric.shadows.ShadowSQLiteConnection ShadowFileUtils::class, ShadowPasswordUtil::class, ], - sdk = [LOLLIPOP, P, Build.VERSION_CODES.R], + sdk = [M, P, Build.VERSION_CODES.R], ) abstract class AbstractOperationsTestBase { private var ctx: Context? = null diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/EditableFileAbstractionTest.java b/app/src/test/java/com/amaze/filemanager/filesystem/EditableFileAbstractionTest.java index 32897ee00e..25964472f7 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/EditableFileAbstractionTest.java +++ b/app/src/test/java/com/amaze/filemanager/filesystem/EditableFileAbstractionTest.java @@ -20,7 +20,7 @@ package com.amaze.filemanager.filesystem; -import static android.os.Build.VERSION_CODES.LOLLIPOP; +import static android.os.Build.VERSION_CODES.M; import static android.os.Build.VERSION_CODES.P; import static com.amaze.filemanager.filesystem.EditableFileAbstraction.Scheme.CONTENT; import static com.amaze.filemanager.filesystem.EditableFileAbstraction.Scheme.FILE; @@ -49,7 +49,7 @@ @RunWith(AndroidJUnit4.class) @Config( shadows = {ShadowMultiDex.class}, - sdk = {LOLLIPOP, P, Build.VERSION_CODES.R}) + sdk = {M, P, Build.VERSION_CODES.R}) public class EditableFileAbstractionTest { @Test(expected = IllegalArgumentException.class) diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/HybridFileTest.kt b/app/src/test/java/com/amaze/filemanager/filesystem/HybridFileTest.kt index 7d1f6267b0..05f9eb8f9e 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/HybridFileTest.kt +++ b/app/src/test/java/com/amaze/filemanager/filesystem/HybridFileTest.kt @@ -23,7 +23,7 @@ package com.amaze.filemanager.filesystem import android.os.Build -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import android.os.Environment import androidx.test.core.app.ApplicationProvider @@ -40,7 +40,7 @@ import java.net.URLDecoder import kotlin.random.Random @RunWith(AndroidJUnit4::class) -@Config(shadows = [ShadowMultiDex::class], sdk = [LOLLIPOP, P, Build.VERSION_CODES.R]) +@Config(shadows = [ShadowMultiDex::class], sdk = [M, P, Build.VERSION_CODES.R]) @Suppress("StringLiteralDuplication") class HybridFileTest { /** diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/OperationsTest.java b/app/src/test/java/com/amaze/filemanager/filesystem/OperationsTest.java index 329e3107e3..dac964e466 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/OperationsTest.java +++ b/app/src/test/java/com/amaze/filemanager/filesystem/OperationsTest.java @@ -20,7 +20,7 @@ package com.amaze.filemanager.filesystem; -import static android.os.Build.VERSION_CODES.LOLLIPOP; +import static android.os.Build.VERSION_CODES.M; import static android.os.Build.VERSION_CODES.P; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -45,7 +45,7 @@ @RunWith(AndroidJUnit4.class) @Config( shadows = {ShadowMultiDex.class}, - sdk = {LOLLIPOP, P, Build.VERSION_CODES.R}) + sdk = {M, P, Build.VERSION_CODES.R}) public class OperationsTest { private File storageRoot = Environment.getExternalStorageDirectory(); diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/RootHelperTest.java b/app/src/test/java/com/amaze/filemanager/filesystem/RootHelperTest.java index f3004396db..7bd64e67ad 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/RootHelperTest.java +++ b/app/src/test/java/com/amaze/filemanager/filesystem/RootHelperTest.java @@ -20,7 +20,7 @@ package com.amaze.filemanager.filesystem; -import static android.os.Build.VERSION_CODES.LOLLIPOP; +import static android.os.Build.VERSION_CODES.M; import static android.os.Build.VERSION_CODES.P; import static org.junit.Assert.fail; @@ -51,7 +51,7 @@ @RunWith(AndroidJUnit4.class) @Config( shadows = {ShadowMultiDex.class}, - sdk = {LOLLIPOP, P, Build.VERSION_CODES.R}) + sdk = {M, P, Build.VERSION_CODES.R}) @Ignore("FIXME: should not ignore - please implement a shadow") public class RootHelperTest { diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/compressed/B0rkenZipTest.java b/app/src/test/java/com/amaze/filemanager/filesystem/compressed/B0rkenZipTest.java index 1047900c01..1ed0c4730d 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/compressed/B0rkenZipTest.java +++ b/app/src/test/java/com/amaze/filemanager/filesystem/compressed/B0rkenZipTest.java @@ -20,7 +20,7 @@ package com.amaze.filemanager.filesystem.compressed; -import static android.os.Build.VERSION_CODES.LOLLIPOP; +import static android.os.Build.VERSION_CODES.M; import static android.os.Build.VERSION_CODES.P; import static kotlin.io.ConstantsKt.DEFAULT_BUFFER_SIZE; import static org.junit.Assert.assertEquals; @@ -56,7 +56,7 @@ @RunWith(AndroidJUnit4.class) @Config( shadows = {ShadowMultiDex.class}, - sdk = {LOLLIPOP, P, Build.VERSION_CODES.R}) + sdk = {M, P, Build.VERSION_CODES.R}) public class B0rkenZipTest { private File zipfile1 = new File(Environment.getExternalStorageDirectory(), "zip-slip.zip"); diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/compressed/CompressedHelperTest.java b/app/src/test/java/com/amaze/filemanager/filesystem/compressed/CompressedHelperTest.java index 0573930e05..e52dc1ce7c 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/compressed/CompressedHelperTest.java +++ b/app/src/test/java/com/amaze/filemanager/filesystem/compressed/CompressedHelperTest.java @@ -20,7 +20,7 @@ package com.amaze.filemanager.filesystem.compressed; -import static android.os.Build.VERSION_CODES.LOLLIPOP; +import static android.os.Build.VERSION_CODES.M; import static android.os.Build.VERSION_CODES.P; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -66,7 +66,7 @@ @RunWith(AndroidJUnit4.class) @Config( shadows = {ShadowMultiDex.class}, - sdk = {LOLLIPOP, P, Build.VERSION_CODES.R}) + sdk = {M, P, Build.VERSION_CODES.R}) public class CompressedHelperTest { private Context context; diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/compressed/extractcontents/AbstractExtractorTest.kt b/app/src/test/java/com/amaze/filemanager/filesystem/compressed/extractcontents/AbstractExtractorTest.kt index 8e2e8e1c45..2187aa2e80 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/compressed/extractcontents/AbstractExtractorTest.kt +++ b/app/src/test/java/com/amaze/filemanager/filesystem/compressed/extractcontents/AbstractExtractorTest.kt @@ -22,7 +22,7 @@ package com.amaze.filemanager.filesystem.compressed.extractcontents import android.content.Context import android.os.Build -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import android.os.Environment import androidx.test.core.app.ApplicationProvider @@ -50,7 +50,7 @@ import java.nio.file.Paths import java.util.TimeZone @RunWith(AndroidJUnit4::class) -@Config(shadows = [ShadowMultiDex::class], sdk = [LOLLIPOP, P, Build.VERSION_CODES.R]) +@Config(shadows = [ShadowMultiDex::class], sdk = [M, P, Build.VERSION_CODES.R]) abstract class AbstractExtractorTest { protected abstract fun extractorClass(): Class diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/files/FileListSorterTest.kt b/app/src/test/java/com/amaze/filemanager/filesystem/files/FileListSorterTest.kt index e2890ed677..67544eb8bd 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/files/FileListSorterTest.kt +++ b/app/src/test/java/com/amaze/filemanager/filesystem/files/FileListSorterTest.kt @@ -43,7 +43,7 @@ import org.robolectric.annotation.Config @RunWith(AndroidJUnit4::class) @Config( shadows = [ShadowMultiDex::class], - sdk = [Build.VERSION_CODES.LOLLIPOP, Build.VERSION_CODES.P, Build.VERSION_CODES.R], + sdk = [Build.VERSION_CODES.M, Build.VERSION_CODES.P, Build.VERSION_CODES.R], ) @Suppress("StringLiteralDuplication", "ComplexMethod", "LongMethod", "LargeClass") class FileListSorterTest { diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/files/FileUtilsTest.kt b/app/src/test/java/com/amaze/filemanager/filesystem/files/FileUtilsTest.kt index a75c54e152..311913f1ac 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/files/FileUtilsTest.kt +++ b/app/src/test/java/com/amaze/filemanager/filesystem/files/FileUtilsTest.kt @@ -21,7 +21,7 @@ package com.amaze.filemanager.filesystem.files import android.os.Build -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import androidx.test.ext.junit.runners.AndroidJUnit4 import com.amaze.filemanager.filesystem.files.FileUtils.getPathsInPath @@ -38,7 +38,7 @@ import java.util.TimeZone @RunWith(AndroidJUnit4::class) @LooperMode(LooperMode.Mode.PAUSED) -@Config(sdk = [LOLLIPOP, P, Build.VERSION_CODES.R]) +@Config(sdk = [M, P, Build.VERSION_CODES.R]) @Suppress("TooManyFunctions", "StringLiteralDuplication") class FileUtilsTest { /** diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/files/sort/DirSortByTest.kt b/app/src/test/java/com/amaze/filemanager/filesystem/files/sort/DirSortByTest.kt index fb00c32fdb..1146a3dd99 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/files/sort/DirSortByTest.kt +++ b/app/src/test/java/com/amaze/filemanager/filesystem/files/sort/DirSortByTest.kt @@ -32,7 +32,7 @@ import kotlin.random.Random @RunWith(AndroidJUnit4::class) @Config( shadows = [ShadowMultiDex::class], - sdk = [Build.VERSION_CODES.LOLLIPOP, Build.VERSION_CODES.P, Build.VERSION_CODES.R], + sdk = [Build.VERSION_CODES.M, Build.VERSION_CODES.P, Build.VERSION_CODES.R], ) class DirSortByTest { /** Tests if [DirSortBy.getDirSortBy] returns the correct [DirSortBy] corresponding to the given index */ diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/files/sort/SortByTest.kt b/app/src/test/java/com/amaze/filemanager/filesystem/files/sort/SortByTest.kt index a851d96afb..84700d0153 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/files/sort/SortByTest.kt +++ b/app/src/test/java/com/amaze/filemanager/filesystem/files/sort/SortByTest.kt @@ -32,7 +32,7 @@ import kotlin.random.Random @RunWith(AndroidJUnit4::class) @Config( shadows = [ShadowMultiDex::class], - sdk = [Build.VERSION_CODES.LOLLIPOP, Build.VERSION_CODES.P, Build.VERSION_CODES.R], + sdk = [Build.VERSION_CODES.M, Build.VERSION_CODES.P, Build.VERSION_CODES.R], ) class SortByTest { /** Tests if [SortBy.getSortBy] returns the correct [SortBy] corresponding to the given index */ diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/files/sort/SortTypeTest.kt b/app/src/test/java/com/amaze/filemanager/filesystem/files/sort/SortTypeTest.kt index ee9bae2172..29d978bb32 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/files/sort/SortTypeTest.kt +++ b/app/src/test/java/com/amaze/filemanager/filesystem/files/sort/SortTypeTest.kt @@ -31,7 +31,7 @@ import org.robolectric.annotation.Config @RunWith(AndroidJUnit4::class) @Config( shadows = [ShadowMultiDex::class], - sdk = [Build.VERSION_CODES.LOLLIPOP, Build.VERSION_CODES.P, Build.VERSION_CODES.R], + sdk = [Build.VERSION_CODES.M, Build.VERSION_CODES.P, Build.VERSION_CODES.R], ) class SortTypeTest { /** Tests if the Int returned from [SortType.toDirectorySortInt] is as expected */ diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/ftp/NetCopyClientConnectionPoolFtpTest.kt b/app/src/test/java/com/amaze/filemanager/filesystem/ftp/NetCopyClientConnectionPoolFtpTest.kt index 35d51316ac..eb8bfb9426 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/ftp/NetCopyClientConnectionPoolFtpTest.kt +++ b/app/src/test/java/com/amaze/filemanager/filesystem/ftp/NetCopyClientConnectionPoolFtpTest.kt @@ -21,7 +21,7 @@ package com.amaze.filemanager.filesystem.ftp import android.os.Build -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import androidx.test.ext.junit.runners.AndroidJUnit4 import com.amaze.filemanager.application.AppConfig @@ -64,7 +64,7 @@ import kotlin.text.Charsets.UTF_8 @RunWith(AndroidJUnit4::class) @Config( shadows = [ShadowMultiDex::class, ShadowPasswordUtil::class], - sdk = [LOLLIPOP, P, Build.VERSION_CODES.R], + sdk = [M, P, Build.VERSION_CODES.R], ) class NetCopyClientConnectionPoolFtpTest { /** diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/ftpserver/commands/AbstractFtpserverCommandTest.kt b/app/src/test/java/com/amaze/filemanager/filesystem/ftpserver/commands/AbstractFtpserverCommandTest.kt index 6aed30ecb4..5b9ed5533a 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/ftpserver/commands/AbstractFtpserverCommandTest.kt +++ b/app/src/test/java/com/amaze/filemanager/filesystem/ftpserver/commands/AbstractFtpserverCommandTest.kt @@ -21,7 +21,7 @@ package com.amaze.filemanager.filesystem.ftpserver.commands import android.os.Build -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import androidx.test.ext.junit.runners.AndroidJUnit4 import com.amaze.filemanager.shadows.ShadowMultiDex @@ -38,7 +38,7 @@ import org.robolectric.annotation.Config @RunWith(AndroidJUnit4::class) @Config( shadows = [ShadowMultiDex::class], - sdk = [LOLLIPOP, P, Build.VERSION_CODES.R], + sdk = [M, P, Build.VERSION_CODES.R], ) abstract class AbstractFtpserverCommandTest { protected lateinit var logger: LogMessageFilter diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/root/ListFilesCommandTest.kt b/app/src/test/java/com/amaze/filemanager/filesystem/root/ListFilesCommandTest.kt index b00c868784..d2216be56a 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/root/ListFilesCommandTest.kt +++ b/app/src/test/java/com/amaze/filemanager/filesystem/root/ListFilesCommandTest.kt @@ -22,7 +22,7 @@ package com.amaze.filemanager.filesystem.root import android.content.SharedPreferences import android.os.Build -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import androidx.preference.PreferenceManager import androidx.test.core.app.ApplicationProvider @@ -54,7 +54,7 @@ import java.io.InputStreamReader @RunWith(AndroidJUnit4::class) @Config( shadows = [ShadowMultiDex::class, ShadowNativeOperations::class], - sdk = [LOLLIPOP, P, Build.VERSION_CODES.R], + sdk = [M, P, Build.VERSION_CODES.R], ) class ListFilesCommandTest { private val sharedPreferences: SharedPreferences = diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/root/ListFilesCommandTest2.kt b/app/src/test/java/com/amaze/filemanager/filesystem/root/ListFilesCommandTest2.kt index 6b828df226..daa421e4f2 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/root/ListFilesCommandTest2.kt +++ b/app/src/test/java/com/amaze/filemanager/filesystem/root/ListFilesCommandTest2.kt @@ -22,7 +22,7 @@ package com.amaze.filemanager.filesystem.root import android.content.SharedPreferences import android.os.Build -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import androidx.preference.PreferenceManager import androidx.test.core.app.ApplicationProvider @@ -54,7 +54,7 @@ import java.io.InputStreamReader @RunWith(AndroidJUnit4::class) @Config( shadows = [ShadowMultiDex::class, ShadowNativeOperations::class], - sdk = [LOLLIPOP, P, Build.VERSION_CODES.R], + sdk = [M, P, Build.VERSION_CODES.R], ) class ListFilesCommandTest2 { private val sharedPreferences: SharedPreferences = diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/smb/CifsContextsTest.java b/app/src/test/java/com/amaze/filemanager/filesystem/smb/CifsContextsTest.java index bb83e42eb4..3759026e9f 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/smb/CifsContextsTest.java +++ b/app/src/test/java/com/amaze/filemanager/filesystem/smb/CifsContextsTest.java @@ -20,7 +20,7 @@ package com.amaze.filemanager.filesystem.smb; -import static android.os.Build.VERSION_CODES.LOLLIPOP; +import static android.os.Build.VERSION_CODES.M; import static android.os.Build.VERSION_CODES.P; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -44,7 +44,7 @@ import jcifs.ResolverType; import jcifs.context.BaseContext; -@Config(sdk = {LOLLIPOP, P, Build.VERSION_CODES.R}) +@Config(sdk = {M, P, Build.VERSION_CODES.R}) @RunWith(AndroidJUnit4.class) public class CifsContextsTest { diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/smb/SmbHybridFileTest.kt b/app/src/test/java/com/amaze/filemanager/filesystem/smb/SmbHybridFileTest.kt index e6995e4ef4..47a95b6a8c 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/smb/SmbHybridFileTest.kt +++ b/app/src/test/java/com/amaze/filemanager/filesystem/smb/SmbHybridFileTest.kt @@ -22,7 +22,7 @@ package com.amaze.filemanager.filesystem.smb import android.content.Context import android.os.Build -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -45,7 +45,7 @@ import org.robolectric.shadows.ShadowSQLiteConnection @RunWith(AndroidJUnit4::class) @Config( shadows = [ShadowSmbUtil::class, ShadowMultiDex::class], - sdk = [LOLLIPOP, P, Build.VERSION_CODES.R], + sdk = [M, P, Build.VERSION_CODES.R], ) @LooperMode(LooperMode.Mode.PAUSED) class SmbHybridFileTest { diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/ssh/AbstractSftpServerTest.kt b/app/src/test/java/com/amaze/filemanager/filesystem/ssh/AbstractSftpServerTest.kt index 708805e08d..8f631c1dec 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/ssh/AbstractSftpServerTest.kt +++ b/app/src/test/java/com/amaze/filemanager/filesystem/ssh/AbstractSftpServerTest.kt @@ -21,7 +21,7 @@ package com.amaze.filemanager.filesystem.ssh import android.os.Build.VERSION_CODES -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import android.os.Environment import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -63,7 +63,7 @@ import kotlin.text.Charsets.UTF_8 @RunWith(AndroidJUnit4::class) @Config( shadows = [ShadowMultiDex::class, ShadowPasswordUtil::class], - sdk = [LOLLIPOP, P, VERSION_CODES.R], + sdk = [M, P, VERSION_CODES.R], ) abstract class AbstractSftpServerTest { protected var encryptedPassword: String? = diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/ssh/NetCopyClientConnectionPoolSshTest.kt b/app/src/test/java/com/amaze/filemanager/filesystem/ssh/NetCopyClientConnectionPoolSshTest.kt index 27b8e5c406..6fd76ec607 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/ssh/NetCopyClientConnectionPoolSshTest.kt +++ b/app/src/test/java/com/amaze/filemanager/filesystem/ssh/NetCopyClientConnectionPoolSshTest.kt @@ -21,7 +21,7 @@ package com.amaze.filemanager.filesystem.ssh import android.os.Build -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import androidx.test.ext.junit.runners.AndroidJUnit4 import com.amaze.filemanager.application.AppConfig @@ -75,7 +75,7 @@ import kotlin.text.Charsets.UTF_8 @RunWith(AndroidJUnit4::class) @Config( shadows = [ShadowMultiDex::class, ShadowPasswordUtil::class], - sdk = [LOLLIPOP, P, Build.VERSION_CODES.R], + sdk = [M, P, Build.VERSION_CODES.R], ) class NetCopyClientConnectionPoolSshTest { /** diff --git a/app/src/test/java/com/amaze/filemanager/filesystem/ssh/SshHybridFileTest.kt b/app/src/test/java/com/amaze/filemanager/filesystem/ssh/SshHybridFileTest.kt index 5c10d396a8..e5ceef2d31 100644 --- a/app/src/test/java/com/amaze/filemanager/filesystem/ssh/SshHybridFileTest.kt +++ b/app/src/test/java/com/amaze/filemanager/filesystem/ssh/SshHybridFileTest.kt @@ -22,7 +22,7 @@ package com.amaze.filemanager.filesystem.ssh import android.content.Context import android.os.Build -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -46,7 +46,7 @@ import org.robolectric.annotation.LooperMode @LooperMode(LooperMode.Mode.PAUSED) @Config( shadows = [ShadowMultiDex::class, ShadowPasswordUtil::class], - sdk = [LOLLIPOP, P, Build.VERSION_CODES.R], + sdk = [M, P, Build.VERSION_CODES.R], ) class SshHybridFileTest { private var ctx: Context? = null diff --git a/app/src/test/java/com/amaze/filemanager/ui/activities/AbstractMainActivityTestBase.kt b/app/src/test/java/com/amaze/filemanager/ui/activities/AbstractMainActivityTestBase.kt index 307828c771..d6291f3a72 100644 --- a/app/src/test/java/com/amaze/filemanager/ui/activities/AbstractMainActivityTestBase.kt +++ b/app/src/test/java/com/amaze/filemanager/ui/activities/AbstractMainActivityTestBase.kt @@ -24,7 +24,7 @@ import android.Manifest import android.content.Context import android.os.Build import android.os.Build.VERSION_CODES -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import android.os.storage.StorageManager import androidx.annotation.NonNull @@ -54,7 +54,7 @@ import org.robolectric.shadows.ShadowStorageManager */ @RunWith(AndroidJUnit4::class) @Config( - sdk = [LOLLIPOP, P, VERSION_CODES.R], + sdk = [M, P, VERSION_CODES.R], shadows = [ ShadowMultiDex::class, ShadowStorageManager::class, diff --git a/app/src/test/java/com/amaze/filemanager/ui/activities/DatabaseViewerActivityTest.kt b/app/src/test/java/com/amaze/filemanager/ui/activities/DatabaseViewerActivityTest.kt index 24f0d60582..564535e7c0 100644 --- a/app/src/test/java/com/amaze/filemanager/ui/activities/DatabaseViewerActivityTest.kt +++ b/app/src/test/java/com/amaze/filemanager/ui/activities/DatabaseViewerActivityTest.kt @@ -22,7 +22,7 @@ package com.amaze.filemanager.ui.activities import android.content.Intent import android.os.Build -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import androidx.test.ext.junit.runners.AndroidJUnit4 import com.amaze.filemanager.shadows.ShadowMultiDex @@ -43,7 +43,7 @@ import java.util.concurrent.TimeUnit */ @RunWith(AndroidJUnit4::class) @Config( - sdk = [LOLLIPOP, P, Build.VERSION_CODES.R], + sdk = [M, P, Build.VERSION_CODES.R], shadows = [ShadowMultiDex::class, ShadowStorageManager::class], ) class DatabaseViewerActivityTest { diff --git a/app/src/test/java/com/amaze/filemanager/ui/activities/PermissionsActivityTest.kt b/app/src/test/java/com/amaze/filemanager/ui/activities/PermissionsActivityTest.kt index c4f178d511..7a25bfe0e1 100644 --- a/app/src/test/java/com/amaze/filemanager/ui/activities/PermissionsActivityTest.kt +++ b/app/src/test/java/com/amaze/filemanager/ui/activities/PermissionsActivityTest.kt @@ -24,7 +24,7 @@ import android.app.AppOpsManager import android.content.Context import android.net.Uri import android.os.Build -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import android.os.Build.VERSION_CODES.R import android.os.storage.StorageManager @@ -64,7 +64,7 @@ import org.robolectric.shadows.ShadowStorageManager */ @RunWith(AndroidJUnit4::class) @Config( - sdk = [LOLLIPOP, P, Build.VERSION_CODES.R], + sdk = [M, P, Build.VERSION_CODES.R], shadows = [ShadowMultiDex::class, ShadowStorageManager::class], ) class PermissionsActivityTest { diff --git a/app/src/test/java/com/amaze/filemanager/ui/activities/TextEditorActivityTest.java b/app/src/test/java/com/amaze/filemanager/ui/activities/TextEditorActivityTest.java index c65a67166c..54d53de765 100644 --- a/app/src/test/java/com/amaze/filemanager/ui/activities/TextEditorActivityTest.java +++ b/app/src/test/java/com/amaze/filemanager/ui/activities/TextEditorActivityTest.java @@ -20,7 +20,7 @@ package com.amaze.filemanager.ui.activities; -import static android.os.Build.VERSION_CODES.LOLLIPOP; +import static android.os.Build.VERSION_CODES.M; import static android.os.Build.VERSION_CODES.P; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -58,7 +58,7 @@ @RunWith(AndroidJUnit4.class) @Config( shadows = {ShadowMultiDex.class}, - sdk = {LOLLIPOP, P, Build.VERSION_CODES.R}) + sdk = {M, P, Build.VERSION_CODES.R}) public class TextEditorActivityTest { private final String fileContents = "fsdfsdfs"; diff --git a/app/src/test/java/com/amaze/filemanager/ui/dialogs/AbstractEncryptDialogTests.kt b/app/src/test/java/com/amaze/filemanager/ui/dialogs/AbstractEncryptDialogTests.kt index 7c4b684f95..2e262d934f 100644 --- a/app/src/test/java/com/amaze/filemanager/ui/dialogs/AbstractEncryptDialogTests.kt +++ b/app/src/test/java/com/amaze/filemanager/ui/dialogs/AbstractEncryptDialogTests.kt @@ -23,14 +23,16 @@ package com.amaze.filemanager.ui.dialogs import android.Manifest import android.os.Build import android.os.Build.VERSION.SDK_INT -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.N import android.os.Build.VERSION_CODES.P import androidx.annotation.RequiresApi import androidx.lifecycle.Lifecycle +import androidx.preference.PreferenceManager import androidx.test.core.app.ActivityScenario import androidx.test.ext.junit.runners.AndroidJUnit4 import androidx.test.rule.GrantPermissionRule +import com.amaze.filemanager.application.AppConfig import com.amaze.filemanager.shadows.ShadowFileUtils import com.amaze.filemanager.shadows.ShadowMultiDex import com.amaze.filemanager.test.ShadowTabHandler @@ -48,7 +50,7 @@ import org.robolectric.annotation.Config @RunWith(AndroidJUnit4::class) @Config( shadows = [ShadowMultiDex::class, ShadowTabHandler::class, ShadowFileUtils::class], - sdk = [LOLLIPOP, P, Build.VERSION_CODES.R], + sdk = [M, P, Build.VERSION_CODES.R], ) abstract class AbstractEncryptDialogTests { protected lateinit var scenario: ActivityScenario @@ -56,7 +58,7 @@ abstract class AbstractEncryptDialogTests { @Rule @JvmField @RequiresApi(Build.VERSION_CODES.R) - var allFilesPermissionRule = + var allFilesPermissionRule: GrantPermissionRule = GrantPermissionRule .grant(Manifest.permission.MANAGE_EXTERNAL_STORAGE) @@ -71,10 +73,14 @@ abstract class AbstractEncryptDialogTests { } /** - * Post test cleanup. + * Post test cleanup. Clear all preferences. */ @After open fun tearDown() { scenario.close() + PreferenceManager.getDefaultSharedPreferences(AppConfig.getInstance()) + .edit() + .clear() + .apply() } } diff --git a/app/src/test/java/com/amaze/filemanager/ui/dialogs/ColorPickerDialogTest.kt b/app/src/test/java/com/amaze/filemanager/ui/dialogs/ColorPickerDialogTest.kt index da53a03bee..ede4e0d9ad 100644 --- a/app/src/test/java/com/amaze/filemanager/ui/dialogs/ColorPickerDialogTest.kt +++ b/app/src/test/java/com/amaze/filemanager/ui/dialogs/ColorPickerDialogTest.kt @@ -21,7 +21,7 @@ package com.amaze.filemanager.ui.dialogs import android.os.Build.VERSION_CODES -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import androidx.test.ext.junit.runners.AndroidJUnit4 import com.amaze.filemanager.application.AppConfig @@ -42,7 +42,7 @@ import org.robolectric.annotation.Config @RunWith(AndroidJUnit4::class) @Config( shadows = [ShadowMultiDex::class, ShadowTabHandler::class, ShadowFileUtils::class], - sdk = [LOLLIPOP, P, VERSION_CODES.R], + sdk = [M, P, VERSION_CODES.R], ) class ColorPickerDialogTest { /** diff --git a/app/src/test/java/com/amaze/filemanager/ui/dialogs/DecryptFingerprintDialogTest.kt b/app/src/test/java/com/amaze/filemanager/ui/dialogs/DecryptFingerprintDialogTest.kt index b5af6f68a4..2d5cf9d4de 100644 --- a/app/src/test/java/com/amaze/filemanager/ui/dialogs/DecryptFingerprintDialogTest.kt +++ b/app/src/test/java/com/amaze/filemanager/ui/dialogs/DecryptFingerprintDialogTest.kt @@ -49,6 +49,7 @@ import org.junit.Before import org.junit.Test import org.robolectric.Shadows.shadowOf import org.robolectric.annotation.Config +import org.robolectric.shadow.api.Shadow import org.robolectric.shadows.ShadowDialog import org.robolectric.shadows.ShadowFingerprintManager import java.io.File @@ -96,7 +97,7 @@ class DecryptFingerprintDialogTest : AbstractEncryptDialogTests() { fun testDecryptFingerprintDialogSuccess() { performTest( testContent = { - shadowOf( + Shadow.extract( AppConfig.getInstance().getSystemService(FingerprintManager::class.java), ).run { setDefaultFingerprints(1) @@ -121,7 +122,7 @@ class DecryptFingerprintDialogTest : AbstractEncryptDialogTests() { fun testDecryptFingerprintDialogFailed() { performTest( testContent = { - shadowOf( + Shadow.extract( AppConfig.getInstance().getSystemService(FingerprintManager::class.java), ).run { setDefaultFingerprints(1) diff --git a/app/src/test/java/com/amaze/filemanager/ui/fragments/CloudSheetFragmentTest.java b/app/src/test/java/com/amaze/filemanager/ui/fragments/CloudSheetFragmentTest.java index 28ca6edcb3..e7554d2b00 100644 --- a/app/src/test/java/com/amaze/filemanager/ui/fragments/CloudSheetFragmentTest.java +++ b/app/src/test/java/com/amaze/filemanager/ui/fragments/CloudSheetFragmentTest.java @@ -20,7 +20,7 @@ package com.amaze.filemanager.ui.fragments; -import static android.os.Build.VERSION_CODES.LOLLIPOP; +import static android.os.Build.VERSION_CODES.M; import static android.os.Build.VERSION_CODES.P; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -39,7 +39,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; @RunWith(AndroidJUnit4.class) -@Config(sdk = {LOLLIPOP, P, Build.VERSION_CODES.R}) +@Config(sdk = {M, P, Build.VERSION_CODES.R}) public class CloudSheetFragmentTest { @Test diff --git a/app/src/test/java/com/amaze/filemanager/ui/fragments/preferencefragments/UiPrefsFragmentTest.kt b/app/src/test/java/com/amaze/filemanager/ui/fragments/preferencefragments/UiPrefsFragmentTest.kt index 277aaccb33..a997e922df 100644 --- a/app/src/test/java/com/amaze/filemanager/ui/fragments/preferencefragments/UiPrefsFragmentTest.kt +++ b/app/src/test/java/com/amaze/filemanager/ui/fragments/preferencefragments/UiPrefsFragmentTest.kt @@ -52,7 +52,7 @@ import kotlin.random.Random */ @Config( sdk = [ - Build.VERSION_CODES.LOLLIPOP, + Build.VERSION_CODES.M, Build.VERSION_CODES.N, Build.VERSION_CODES.P, Build.VERSION_CODES.R, diff --git a/app/src/test/java/com/amaze/filemanager/ui/icons/IconsTest.java b/app/src/test/java/com/amaze/filemanager/ui/icons/IconsTest.java index 39ace0bde4..17e6e939b0 100644 --- a/app/src/test/java/com/amaze/filemanager/ui/icons/IconsTest.java +++ b/app/src/test/java/com/amaze/filemanager/ui/icons/IconsTest.java @@ -20,15 +20,15 @@ package com.amaze.filemanager.ui.icons; -import static android.os.Build.VERSION_CODES.LOLLIPOP; +import static android.os.Build.VERSION_CODES.M; import static android.os.Build.VERSION_CODES.P; import static org.junit.Assert.assertEquals; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.robolectric.Shadows; import org.robolectric.annotation.Config; +import org.robolectric.shadow.api.Shadow; import org.robolectric.shadows.ShadowMimeTypeMap; import com.amaze.filemanager.shadows.ShadowMultiDex; @@ -41,13 +41,13 @@ @RunWith(AndroidJUnit4.class) @Config( shadows = {ShadowMultiDex.class}, - sdk = {LOLLIPOP, P, Build.VERSION_CODES.R}) + sdk = {M, P, Build.VERSION_CODES.R}) public class IconsTest { @Before public void setUp() { // By default Robolectric's MimeTypeMap is empty, we need to populate them - ShadowMimeTypeMap mimeTypeMap = Shadows.shadowOf(MimeTypeMap.getSingleton()); + ShadowMimeTypeMap mimeTypeMap = Shadow.extract(MimeTypeMap.getSingleton()); mimeTypeMap.addExtensionMimeTypeMapping("zip", "application/zip"); mimeTypeMap.addExtensionMimeTypeMapping("rar", "application/x-rar-compressed"); mimeTypeMap.addExtensionMimeTypeMapping("tar", "application/x-tar"); diff --git a/app/src/test/java/com/amaze/filemanager/ui/notifications/NotificationConstantsTest.java b/app/src/test/java/com/amaze/filemanager/ui/notifications/NotificationConstantsTest.java index f9c5e4b8ea..758431e5c2 100644 --- a/app/src/test/java/com/amaze/filemanager/ui/notifications/NotificationConstantsTest.java +++ b/app/src/test/java/com/amaze/filemanager/ui/notifications/NotificationConstantsTest.java @@ -22,7 +22,7 @@ import static android.app.NotificationManager.IMPORTANCE_HIGH; import static android.app.NotificationManager.IMPORTANCE_MIN; -import static android.os.Build.VERSION_CODES.LOLLIPOP; +import static android.os.Build.VERSION_CODES.M; import static android.os.Build.VERSION_CODES.P; import static com.amaze.filemanager.ui.notifications.NotificationConstants.CHANNEL_FTP_ID; import static com.amaze.filemanager.ui.notifications.NotificationConstants.CHANNEL_NORMAL_ID; @@ -54,7 +54,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; @RunWith(AndroidJUnit4.class) -@Config(sdk = {LOLLIPOP, P, Build.VERSION_CODES.R}) +@Config(sdk = {M, P, Build.VERSION_CODES.R}) public class NotificationConstantsTest { private Context context; @@ -89,7 +89,7 @@ public void testSetMetadataIllegalType() { } @Test - @Config(sdk = {LOLLIPOP}) // max sdk is N + @Config(sdk = {M}) // max sdk is N public void testNormalNotification() { NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_NORMAL_ID) @@ -101,7 +101,7 @@ public void testNormalNotification() { NotificationConstants.setMetadata(context, builder, TYPE_NORMAL); Notification result = builder.build(); - if (Build.VERSION.SDK_INT >= LOLLIPOP) { + if (Build.VERSION.SDK_INT >= M) { assertEquals(Notification.CATEGORY_SERVICE, result.category); } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { @@ -112,7 +112,7 @@ public void testNormalNotification() { } @Test - @Config(sdk = {LOLLIPOP}) // max sdk is N + @Config(sdk = {M}) // max sdk is N public void testFtpNotification() { NotificationCompat.Builder builder = new NotificationCompat.Builder(context, CHANNEL_FTP_ID) @@ -124,7 +124,7 @@ public void testFtpNotification() { .setOnlyAlertOnce(true); NotificationConstants.setMetadata(context, builder, TYPE_FTP); Notification result = builder.build(); - if (Build.VERSION.SDK_INT >= LOLLIPOP) { + if (Build.VERSION.SDK_INT >= M) { assertEquals(Notification.CATEGORY_SERVICE, result.category); assertEquals(Notification.VISIBILITY_PUBLIC, result.visibility); } diff --git a/app/src/test/java/com/amaze/filemanager/ui/theme/AppThemeTest.kt b/app/src/test/java/com/amaze/filemanager/ui/theme/AppThemeTest.kt index 7d614b8431..d421c5d5d0 100644 --- a/app/src/test/java/com/amaze/filemanager/ui/theme/AppThemeTest.kt +++ b/app/src/test/java/com/amaze/filemanager/ui/theme/AppThemeTest.kt @@ -22,7 +22,7 @@ package com.amaze.filemanager.ui.theme import android.content.Context import android.os.Build -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import android.os.PowerManager import androidx.preference.PreferenceManager @@ -41,7 +41,7 @@ import java.util.Calendar @RunWith(AndroidJUnit4::class) @Config( - sdk = [LOLLIPOP, P, Build.VERSION_CODES.R], + sdk = [M, P, Build.VERSION_CODES.R], shadows = [ShadowMultiDex::class], ) class AppThemeTest { diff --git a/app/src/test/java/com/amaze/filemanager/ui/views/WarnableTextInputValidatorTest.java b/app/src/test/java/com/amaze/filemanager/ui/views/WarnableTextInputValidatorTest.java index 37070cd432..f7096ace25 100644 --- a/app/src/test/java/com/amaze/filemanager/ui/views/WarnableTextInputValidatorTest.java +++ b/app/src/test/java/com/amaze/filemanager/ui/views/WarnableTextInputValidatorTest.java @@ -20,7 +20,7 @@ package com.amaze.filemanager.ui.views; -import static android.os.Build.VERSION_CODES.LOLLIPOP; +import static android.os.Build.VERSION_CODES.M; import static android.os.Build.VERSION_CODES.P; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -44,7 +44,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; @RunWith(AndroidJUnit4.class) -@Config(sdk = {LOLLIPOP, P, Build.VERSION_CODES.R}) +@Config(sdk = {M, P, Build.VERSION_CODES.R}) public class WarnableTextInputValidatorTest { private Context context; diff --git a/app/src/test/java/com/amaze/filemanager/utils/AESCryptTest.kt b/app/src/test/java/com/amaze/filemanager/utils/AESCryptTest.kt index 7559fa97d4..c7c9bad0e9 100644 --- a/app/src/test/java/com/amaze/filemanager/utils/AESCryptTest.kt +++ b/app/src/test/java/com/amaze/filemanager/utils/AESCryptTest.kt @@ -21,7 +21,7 @@ package com.amaze.filemanager.utils import android.os.Build -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import androidx.test.ext.junit.runners.AndroidJUnit4 import org.junit.Assert.assertArrayEquals @@ -36,7 +36,7 @@ import kotlin.random.Random * Unit test for [AESCrypt] */ @RunWith(AndroidJUnit4::class) -@Config(sdk = [LOLLIPOP, P, Build.VERSION_CODES.R]) +@Config(sdk = [M, P, Build.VERSION_CODES.R]) class AESCryptTest { /** * Simple sanity test on [AESCrypt]. diff --git a/app/src/test/java/com/amaze/filemanager/utils/AnimUtilsTest.java b/app/src/test/java/com/amaze/filemanager/utils/AnimUtilsTest.java index 92b65fdc29..24df7b4724 100644 --- a/app/src/test/java/com/amaze/filemanager/utils/AnimUtilsTest.java +++ b/app/src/test/java/com/amaze/filemanager/utils/AnimUtilsTest.java @@ -20,7 +20,7 @@ package com.amaze.filemanager.utils; -import static android.os.Build.VERSION_CODES.LOLLIPOP; +import static android.os.Build.VERSION_CODES.M; import static android.os.Build.VERSION_CODES.P; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; @@ -45,7 +45,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; @RunWith(AndroidJUnit4.class) -@Config(sdk = {LOLLIPOP, P, Build.VERSION_CODES.R}) +@Config(sdk = {M, P, Build.VERSION_CODES.R}) public class AnimUtilsTest { @Test diff --git a/app/src/test/java/com/amaze/filemanager/utils/CryptUtilTest.kt b/app/src/test/java/com/amaze/filemanager/utils/CryptUtilTest.kt index d7e116593f..6b51727d64 100644 --- a/app/src/test/java/com/amaze/filemanager/utils/CryptUtilTest.kt +++ b/app/src/test/java/com/amaze/filemanager/utils/CryptUtilTest.kt @@ -21,7 +21,7 @@ package com.amaze.filemanager.utils import android.os.Build -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import android.os.Environment import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -48,7 +48,7 @@ import kotlin.random.Random @RunWith(AndroidJUnit4::class) @Config( - sdk = [LOLLIPOP, P, Build.VERSION_CODES.R], + sdk = [M, P, Build.VERSION_CODES.R], ) class CryptUtilTest { /** diff --git a/app/src/test/java/com/amaze/filemanager/utils/MinMaxInputFilterTest.kt b/app/src/test/java/com/amaze/filemanager/utils/MinMaxInputFilterTest.kt index 0e882b12c8..7f3d2df94b 100644 --- a/app/src/test/java/com/amaze/filemanager/utils/MinMaxInputFilterTest.kt +++ b/app/src/test/java/com/amaze/filemanager/utils/MinMaxInputFilterTest.kt @@ -21,7 +21,7 @@ package com.amaze.filemanager.utils import android.os.Build -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import android.text.SpannedString import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -32,7 +32,7 @@ import org.junit.runner.RunWith import org.robolectric.annotation.Config @RunWith(AndroidJUnit4::class) -@Config(sdk = [LOLLIPOP, P, Build.VERSION_CODES.R]) +@Config(sdk = [M, P, Build.VERSION_CODES.R]) class MinMaxInputFilterTest { /** * Test MinMaxInputFilter functioning diff --git a/app/src/test/java/com/amaze/filemanager/utils/NetworkUtilTest.kt b/app/src/test/java/com/amaze/filemanager/utils/NetworkUtilTest.kt index 05e452debb..d13a4ffb72 100644 --- a/app/src/test/java/com/amaze/filemanager/utils/NetworkUtilTest.kt +++ b/app/src/test/java/com/amaze/filemanager/utils/NetworkUtilTest.kt @@ -30,7 +30,7 @@ import android.net.wifi.WifiInfo import android.net.wifi.WifiManager import android.os.Build import android.os.Build.VERSION_CODES -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import androidx.test.ext.junit.runners.AndroidJUnit4 import io.mockk.every @@ -53,7 +53,7 @@ import java.util.Collections * Tests for [NetworkUtil]. */ @RunWith(AndroidJUnit4::class) -@Config(sdk = [LOLLIPOP, P, VERSION_CODES.R]) +@Config(sdk = [M, P, VERSION_CODES.R]) @Suppress("StringLiteralDuplication") class NetworkUtilTest { private lateinit var context: Context diff --git a/app/src/test/java/com/amaze/filemanager/utils/SmbUtilTest.kt b/app/src/test/java/com/amaze/filemanager/utils/SmbUtilTest.kt index ccc65a0110..c5f498799b 100644 --- a/app/src/test/java/com/amaze/filemanager/utils/SmbUtilTest.kt +++ b/app/src/test/java/com/amaze/filemanager/utils/SmbUtilTest.kt @@ -21,7 +21,7 @@ package com.amaze.filemanager.utils import android.os.Build -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 @@ -46,7 +46,7 @@ import org.robolectric.annotation.Config @Suppress("StringLiteralDuplication") @RunWith(AndroidJUnit4::class) @Config( - sdk = [LOLLIPOP, P, Build.VERSION_CODES.R], + sdk = [M, P, Build.VERSION_CODES.R], shadows = [ShadowPasswordUtil::class, ShadowSmbUtil::class], ) class SmbUtilTest { diff --git a/app/src/test/java/com/amaze/filemanager/utils/TinyDBTest.java b/app/src/test/java/com/amaze/filemanager/utils/TinyDBTest.java index 12e9f3cd13..aeff06a154 100644 --- a/app/src/test/java/com/amaze/filemanager/utils/TinyDBTest.java +++ b/app/src/test/java/com/amaze/filemanager/utils/TinyDBTest.java @@ -20,7 +20,7 @@ package com.amaze.filemanager.utils; -import static android.os.Build.VERSION_CODES.LOLLIPOP; +import static android.os.Build.VERSION_CODES.M; import static android.os.Build.VERSION_CODES.P; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertNull; @@ -38,7 +38,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; @RunWith(AndroidJUnit4.class) -@Config(sdk = {LOLLIPOP, P, Build.VERSION_CODES.R}) +@Config(sdk = {M, P, Build.VERSION_CODES.R}) public class TinyDBTest { private SharedPreferences prefs; diff --git a/app/src/test/java/com/amaze/filemanager/utils/UtilsTest.java b/app/src/test/java/com/amaze/filemanager/utils/UtilsTest.java index fa90467fca..d25e9e8a49 100644 --- a/app/src/test/java/com/amaze/filemanager/utils/UtilsTest.java +++ b/app/src/test/java/com/amaze/filemanager/utils/UtilsTest.java @@ -20,7 +20,7 @@ package com.amaze.filemanager.utils; -import static android.os.Build.VERSION_CODES.LOLLIPOP; +import static android.os.Build.VERSION_CODES.M; import static android.os.Build.VERSION_CODES.N; import static android.os.Build.VERSION_CODES.P; import static com.amaze.filemanager.utils.Utils.formatTimer; @@ -56,7 +56,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; @RunWith(AndroidJUnit4.class) -@Config(sdk = {LOLLIPOP, P, Build.VERSION_CODES.R}) +@Config(sdk = {M, P, Build.VERSION_CODES.R}) public class UtilsTest { @Test diff --git a/app/src/test/java/com/amaze/filemanager/utils/X509CertificateUtilTest.kt b/app/src/test/java/com/amaze/filemanager/utils/X509CertificateUtilTest.kt index fd74085121..ebfc7a2700 100644 --- a/app/src/test/java/com/amaze/filemanager/utils/X509CertificateUtilTest.kt +++ b/app/src/test/java/com/amaze/filemanager/utils/X509CertificateUtilTest.kt @@ -21,7 +21,7 @@ package com.amaze.filemanager.utils import android.os.Build -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import androidx.test.ext.junit.runners.AndroidJUnit4 import com.amaze.filemanager.shadows.ShadowMultiDex @@ -41,7 +41,7 @@ import java.security.cert.X509Certificate @RunWith(AndroidJUnit4::class) @Config( shadows = [ShadowMultiDex::class], - sdk = [LOLLIPOP, P, Build.VERSION_CODES.R], + sdk = [M, P, Build.VERSION_CODES.R], ) class X509CertificateUtilTest { private lateinit var cert: X509Certificate diff --git a/app/src/test/java/com/amaze/filemanager/utils/smb/AbstractSubnetDiscoverDevicesStrategyTests.kt b/app/src/test/java/com/amaze/filemanager/utils/smb/AbstractSubnetDiscoverDevicesStrategyTests.kt index d937bc0c06..c8e8e9783b 100644 --- a/app/src/test/java/com/amaze/filemanager/utils/smb/AbstractSubnetDiscoverDevicesStrategyTests.kt +++ b/app/src/test/java/com/amaze/filemanager/utils/smb/AbstractSubnetDiscoverDevicesStrategyTests.kt @@ -21,7 +21,7 @@ package com.amaze.filemanager.utils.smb import android.os.Build.VERSION_CODES -import android.os.Build.VERSION_CODES.LOLLIPOP +import android.os.Build.VERSION_CODES.M import android.os.Build.VERSION_CODES.P import androidx.test.ext.junit.runners.AndroidJUnit4 import com.amaze.filemanager.utils.NetworkUtil @@ -38,7 +38,7 @@ import java.net.InetAddress * Base class for [SmbDeviceScannerObservable.DiscoverDeviceStrategy] tests. */ @RunWith(AndroidJUnit4::class) -@Config(sdk = [LOLLIPOP, P, VERSION_CODES.R]) +@Config(sdk = [M, P, VERSION_CODES.R]) abstract class AbstractSubnetDiscoverDevicesStrategyTests { /** * Post test cleanup. diff --git a/app/src/testPlay/java/com/amaze/filemanager/filesystem/compressed/extractcontents/MultipartRarExtractorTest.kt b/app/src/testPlay/java/com/amaze/filemanager/filesystem/compressed/extractcontents/MultipartRarExtractorTest.kt index c811673e18..0ab5ac472c 100644 --- a/app/src/testPlay/java/com/amaze/filemanager/filesystem/compressed/extractcontents/MultipartRarExtractorTest.kt +++ b/app/src/testPlay/java/com/amaze/filemanager/filesystem/compressed/extractcontents/MultipartRarExtractorTest.kt @@ -43,7 +43,7 @@ import java.util.concurrent.CountDownLatch @RunWith(AndroidJUnit4::class) @Config( shadows = [ShadowMultiDex::class], - sdk = [Build.VERSION_CODES.LOLLIPOP, Build.VERSION_CODES.P], + sdk = [Build.VERSION_CODES.M, Build.VERSION_CODES.P], ) class MultipartRarExtractorTest { private val callback = diff --git a/build.gradle b/build.gradle index d24894a4b5..a9f3eab387 100644 --- a/build.gradle +++ b/build.gradle @@ -74,6 +74,7 @@ configurations { robo33 robo34 robo35 + robo36 } dependencies { @@ -91,28 +92,24 @@ dependencies { robo32 "org.robolectric:android-all-instrumented:12.1-robolectric-8229987-i7" robo33 "org.robolectric:android-all-instrumented:13-robolectric-9030017-i7" robo34 "org.robolectric:android-all-instrumented:14-robolectric-10818077-i7" - robo35 "org.robolectric:android-all-instrumented:15-robolectric-12650502-i7" + robo35 "org.robolectric:android-all-instrumented:15-robolectric-13954326-i7" + robo36 "org.robolectric:android-all-instrumented:16-robolectric-13921718-i7" } def robolectricDependencies = "${rootProject.layout.buildDirectory.get().asFile}/robolectric" +def robolectricApis = (21..36) + +def fetchRobolectricApiTasks = robolectricApis.collect { apiLevel -> + def configurationName = "robo${apiLevel}" + def taskName = "fetchRobolectric${apiLevel}" + tasks.register(taskName, Copy) { + from configurations.named(configurationName) + into robolectricDependencies + } +} tasks.register('fetchRobolectricDependencies', Copy) { - from configurations.robo21 - from configurations.robo22 - from configurations.robo23 - from configurations.robo24 - from configurations.robo25 - from configurations.robo26 - from configurations.robo27 - from configurations.robo28 - from configurations.robo29 - from configurations.robo30 - from configurations.robo31 - from configurations.robo32 - from configurations.robo33 - from configurations.robo34 - from configurations.robo35 - into robolectricDependencies + dependsOn fetchRobolectricApiTasks } subprojects { diff --git a/testShared/src/test/java/com/amaze/filemanager/test/ShadowPasswordUtilTest.java b/testShared/src/test/java/com/amaze/filemanager/test/ShadowPasswordUtilTest.java index c1f8919b50..b0dd8d2061 100644 --- a/testShared/src/test/java/com/amaze/filemanager/test/ShadowPasswordUtilTest.java +++ b/testShared/src/test/java/com/amaze/filemanager/test/ShadowPasswordUtilTest.java @@ -20,7 +20,7 @@ package com.amaze.filemanager.test; -import static android.os.Build.VERSION_CODES.LOLLIPOP; +import static android.os.Build.VERSION_CODES.M; import static android.os.Build.VERSION_CODES.P; import static org.awaitility.Awaitility.await; import static org.junit.Assert.assertEquals; @@ -56,7 +56,7 @@ @RunWith(AndroidJUnit4.class) @Config( shadows = {ShadowMultiDex.class, ShadowPasswordUtil.class}, - sdk = {LOLLIPOP, P, Build.VERSION_CODES.R}) + sdk = {M, P, Build.VERSION_CODES.R}) public class ShadowPasswordUtilTest { @Before From 272d3fcbd25d8d8a0e69c77cdd495b441a563376 Mon Sep 17 00:00:00 2001 From: Raymond Lai Date: Mon, 10 Aug 2026 23:51:35 +0800 Subject: [PATCH 4/8] Compile with SDK 36 Also upgraded libraries: - Robolectric: 4.16.1 - Glide: 5.0.7 - Bouncy Castle 1.85.2 - Google Play Android Billing: 9.1.0 --- gradle/libs.versions.toml | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 16ee06a521..e36c9650f3 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,7 +1,7 @@ [versions] -compileSdk = "35" -minSdk = "21" -targetSdk = "35" +compileSdk = "36" +minSdk = "23" +targetSdk = "36" kotlin = "2.2.20" ndk = "28.2.13676358" #r28c @@ -11,14 +11,15 @@ gradle = "8.13.2" easylauncher = "6.1.0" legacySupportV13 = "1.0.0" systembartint = "1.0.4" -robolectric = "4.15" -glide = "5.0.5" +robolectric = "4.16.1" +glide = "5.0.7" sshj = "0.40.0" jcifs = "2.1.10" eventbus = "3.3.1" fabSpeedDial = "3.3.0" room = "2.5.2" -bouncyCastle = "1.85" +bouncyCastle = "1.85.2" +bouncyCastlePkix = "1.85" awaitility = "4.3.0" androidXActivity = "1.7.2" androidXCore = "1.16.0" @@ -47,7 +48,7 @@ apacheMina = "2.2.9" mockito = "5.23.0" mockitoInline = "5.2.0" mockitoKotlin = "6.3.0" -androidBilling = "8.0.0" +androidBilling = "9.1.0" cloudrailSiAndroid = "2.22.4" junrar = "8.1.0" vectordrawableAnimated = "1.2.0" @@ -108,7 +109,7 @@ androidX-test-uiautomator = { module = "androidx.test.uiautomator:uiautomator", auto-service = { module = "com.google.auto.service:auto-service", version.ref = "autoService" } -bcpkix-jdk18on = { module = "org.bouncycastle:bcpkix-jdk18on", version.ref = "bouncyCastle" } +bcpkix-jdk18on = { module = "org.bouncycastle:bcpkix-jdk18on", version.ref = "bouncyCastlePkix" } bcprov-jdk18on = { module = "org.bouncycastle:bcprov-jdk18on", version.ref = "bouncyCastle" } apache-mina-core = { module = "org.apache.mina:mina-core", version.ref = "apacheMina" } From 119a58c132bfe45618eb0cfbdda6daea69f19cb4 Mon Sep 17 00:00:00 2001 From: Raymond Lai Date: Tue, 11 Aug 2026 00:10:07 +0800 Subject: [PATCH 5/8] Moved testShared a common module for test classes Per recommendation for proper source management --- app/build.gradle | 7 +- file_operations/build.gradle | 5 +- settings.gradle | 2 +- testShared/build.gradle | 81 +++++++++++++++++++ .../filemanager/shadows/ShadowFileUtils.kt | 0 .../filemanager/shadows/ShadowMultiDex.java | 0 .../filemanager/shadows/ShadowSmbUtil.kt | 0 .../shadows/jcifs/smb/ShadowSmbFile.java | 0 .../filemanager/test/DummyFileGenerator.java | 0 .../test/ShadowNativeOperations.java | 0 .../filemanager/test/ShadowPasswordUtil.kt | 0 .../test/ShadowPasswordUtilTest.java | 0 .../filemanager/test/ShadowTabHandler.kt | 0 .../com/amaze/filemanager/test/TestUtils.kt | 0 14 files changed, 85 insertions(+), 10 deletions(-) create mode 100644 testShared/build.gradle rename testShared/src/{test => main}/java/com/amaze/filemanager/shadows/ShadowFileUtils.kt (100%) rename testShared/src/{test => main}/java/com/amaze/filemanager/shadows/ShadowMultiDex.java (100%) rename testShared/src/{test => main}/java/com/amaze/filemanager/shadows/ShadowSmbUtil.kt (100%) rename testShared/src/{test => main}/java/com/amaze/filemanager/shadows/jcifs/smb/ShadowSmbFile.java (100%) rename testShared/src/{test => main}/java/com/amaze/filemanager/test/DummyFileGenerator.java (100%) rename testShared/src/{test => main}/java/com/amaze/filemanager/test/ShadowNativeOperations.java (100%) rename testShared/src/{test => main}/java/com/amaze/filemanager/test/ShadowPasswordUtil.kt (100%) rename testShared/src/{test => main}/java/com/amaze/filemanager/test/ShadowPasswordUtilTest.java (100%) rename testShared/src/{test => main}/java/com/amaze/filemanager/test/ShadowTabHandler.kt (100%) rename testShared/src/{test => main}/java/com/amaze/filemanager/test/TestUtils.kt (100%) diff --git a/app/build.gradle b/app/build.gradle index bd16fcc929..ebe36ad437 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -98,10 +98,6 @@ android { includeInBundle = false } - sourceSets { - test.java.srcDirs += '../testShared/src/test/java' - } - compileOptions { sourceCompatibility JavaVersion.VERSION_21 targetCompatibility JavaVersion.VERSION_21 @@ -158,7 +154,7 @@ dependencies { ksp libs.androidX.annotation //For tests - kspTest libs.auto.service + testImplementation project(':testShared') testImplementation libs.junit//tests the app logic testImplementation libs.robolectric//tests android interaction testImplementation libs.robolectric.shadows.httpclient//tests android interaction @@ -180,6 +176,7 @@ dependencies { testImplementation libs.kotlin.coroutine.test testImplementation libs.androidX.core.testing testImplementation libs.logback.classic + kspTest libs.auto.service androidTestImplementation libs.junit //tests the app logic androidTestImplementation libs.androidX.test.expresso diff --git a/file_operations/build.gradle b/file_operations/build.gradle index 3c8f78aebc..3f5cf32335 100644 --- a/file_operations/build.gradle +++ b/file_operations/build.gradle @@ -26,10 +26,6 @@ android { } } - sourceSets { - test.java.srcDirs += '../testShared/src/test/java' - } - compileOptions { sourceCompatibility JavaVersion.VERSION_21 targetCompatibility JavaVersion.VERSION_21 @@ -106,6 +102,7 @@ dependencies { //TODO some libs are not needed //For tests + testImplementation project(':testShared') testImplementation libs.junit //tests the app logic testImplementation libs.robolectric //tests android interaction testImplementation libs.robolectric.shadows.httpclient //tests android interaction diff --git a/settings.gradle b/settings.gradle index 0023200c52..cb1e87c6e5 100644 --- a/settings.gradle +++ b/settings.gradle @@ -3,4 +3,4 @@ plugins { } include ':file_operations' include ':portscanner' -include ':app', ':commons_compress_7z' +include ':app', ':commons_compress_7z', ':testShared' diff --git a/testShared/build.gradle b/testShared/build.gradle new file mode 100644 index 0000000000..12d423a853 --- /dev/null +++ b/testShared/build.gradle @@ -0,0 +1,81 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' + +android { + namespace "com.amaze.filemanager.test" + compileSdkVersion libs.versions.compileSdk.get().toInteger() + + defaultConfig { + minSdkVersion libs.versions.minSdk.get().toInteger() + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + flavorDimensions = ['static'] + + productFlavors { + fdroid { + dimension 'static' + } + + play { + dimension 'static' + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_21 + targetCompatibility JavaVersion.VERSION_21 + } + + testOptions { + unitTests { + includeAndroidResources = true + returnDefaultValues = true + } + } +} + +kotlin { + jvmToolchain(21) +} + +dependencies { + // App module dependency for accessing app classes + implementation project(':app') + + // File operations module for NativeOperations + implementation project(':file_operations') + + // Core testing dependencies + implementation libs.junit + implementation libs.robolectric + implementation libs.robolectric.shadows.httpclient + implementation libs.androidX.test.core + implementation libs.androidX.test.runner + implementation libs.androidX.test.rules + implementation libs.androidX.test.ext.junit + implementation libs.mockito.core + implementation libs.androidX.multidex + implementation libs.awaitility + + // Kotlin standard library + implementation libs.kotlin.stdlib.jdk8 + + // MockK for Kotlin mocking + implementation libs.mockk + + // RxJava for Completable and reactive types + implementation libs.rxjava + implementation libs.rxandroid + + // Room for database classes + implementation libs.room.runtime + + // SMB for shadow implementations + implementation libs.jcifs.ng + + // Android dependencies + implementation libs.androidX.appcompat + implementation libs.androidX.fragment +} + diff --git a/testShared/src/test/java/com/amaze/filemanager/shadows/ShadowFileUtils.kt b/testShared/src/main/java/com/amaze/filemanager/shadows/ShadowFileUtils.kt similarity index 100% rename from testShared/src/test/java/com/amaze/filemanager/shadows/ShadowFileUtils.kt rename to testShared/src/main/java/com/amaze/filemanager/shadows/ShadowFileUtils.kt diff --git a/testShared/src/test/java/com/amaze/filemanager/shadows/ShadowMultiDex.java b/testShared/src/main/java/com/amaze/filemanager/shadows/ShadowMultiDex.java similarity index 100% rename from testShared/src/test/java/com/amaze/filemanager/shadows/ShadowMultiDex.java rename to testShared/src/main/java/com/amaze/filemanager/shadows/ShadowMultiDex.java diff --git a/testShared/src/test/java/com/amaze/filemanager/shadows/ShadowSmbUtil.kt b/testShared/src/main/java/com/amaze/filemanager/shadows/ShadowSmbUtil.kt similarity index 100% rename from testShared/src/test/java/com/amaze/filemanager/shadows/ShadowSmbUtil.kt rename to testShared/src/main/java/com/amaze/filemanager/shadows/ShadowSmbUtil.kt diff --git a/testShared/src/test/java/com/amaze/filemanager/shadows/jcifs/smb/ShadowSmbFile.java b/testShared/src/main/java/com/amaze/filemanager/shadows/jcifs/smb/ShadowSmbFile.java similarity index 100% rename from testShared/src/test/java/com/amaze/filemanager/shadows/jcifs/smb/ShadowSmbFile.java rename to testShared/src/main/java/com/amaze/filemanager/shadows/jcifs/smb/ShadowSmbFile.java diff --git a/testShared/src/test/java/com/amaze/filemanager/test/DummyFileGenerator.java b/testShared/src/main/java/com/amaze/filemanager/test/DummyFileGenerator.java similarity index 100% rename from testShared/src/test/java/com/amaze/filemanager/test/DummyFileGenerator.java rename to testShared/src/main/java/com/amaze/filemanager/test/DummyFileGenerator.java diff --git a/testShared/src/test/java/com/amaze/filemanager/test/ShadowNativeOperations.java b/testShared/src/main/java/com/amaze/filemanager/test/ShadowNativeOperations.java similarity index 100% rename from testShared/src/test/java/com/amaze/filemanager/test/ShadowNativeOperations.java rename to testShared/src/main/java/com/amaze/filemanager/test/ShadowNativeOperations.java diff --git a/testShared/src/test/java/com/amaze/filemanager/test/ShadowPasswordUtil.kt b/testShared/src/main/java/com/amaze/filemanager/test/ShadowPasswordUtil.kt similarity index 100% rename from testShared/src/test/java/com/amaze/filemanager/test/ShadowPasswordUtil.kt rename to testShared/src/main/java/com/amaze/filemanager/test/ShadowPasswordUtil.kt diff --git a/testShared/src/test/java/com/amaze/filemanager/test/ShadowPasswordUtilTest.java b/testShared/src/main/java/com/amaze/filemanager/test/ShadowPasswordUtilTest.java similarity index 100% rename from testShared/src/test/java/com/amaze/filemanager/test/ShadowPasswordUtilTest.java rename to testShared/src/main/java/com/amaze/filemanager/test/ShadowPasswordUtilTest.java diff --git a/testShared/src/test/java/com/amaze/filemanager/test/ShadowTabHandler.kt b/testShared/src/main/java/com/amaze/filemanager/test/ShadowTabHandler.kt similarity index 100% rename from testShared/src/test/java/com/amaze/filemanager/test/ShadowTabHandler.kt rename to testShared/src/main/java/com/amaze/filemanager/test/ShadowTabHandler.kt diff --git a/testShared/src/test/java/com/amaze/filemanager/test/TestUtils.kt b/testShared/src/main/java/com/amaze/filemanager/test/TestUtils.kt similarity index 100% rename from testShared/src/test/java/com/amaze/filemanager/test/TestUtils.kt rename to testShared/src/main/java/com/amaze/filemanager/test/TestUtils.kt From e325d0c2ce4ad4eed6470c345d71814753e591d5 Mon Sep 17 00:00:00 2001 From: Raymond Lai Date: Sat, 5 Sep 2026 11:18:14 +0800 Subject: [PATCH 6/8] Changes per PR feedback - ZipHelperCallable throws ArchiveException right away upon processing zero byte zips - i18n string name update: error_unsupported_v5_rar -> error_unsupported_rar_version - bump slf4j and junrar dependencies --- .../junrar/exception/UnsupportedRarVersionException.java | 8 ++++++++ .../asynchronous/asynctasks/compress/ZipHelperCallable.kt | 4 ++-- .../asynchronous/asynctasks/movecopy/PreparePasteTask.kt | 2 +- .../filemanager/asynchronous/services/ExtractService.java | 2 +- .../ui/fragments/CompressedExplorerFragment.kt | 2 +- app/src/main/res/values-ar/strings.xml | 2 +- app/src/main/res/values-cs/strings.xml | 2 +- app/src/main/res/values-de/strings.xml | 2 +- app/src/main/res/values-el/strings.xml | 2 +- app/src/main/res/values-es/strings.xml | 1 + app/src/main/res/values-fr/strings.xml | 2 +- app/src/main/res/values-he/strings.xml | 2 +- app/src/main/res/values-hu-rHU/strings.xml | 2 +- app/src/main/res/values-id/strings.xml | 2 +- app/src/main/res/values-it-rIT/strings.xml | 2 +- app/src/main/res/values-my/strings.xml | 2 +- app/src/main/res/values-pl/strings.xml | 2 +- app/src/main/res/values-pt-rBR/strings.xml | 2 +- app/src/main/res/values-pt-rPT/strings.xml | 2 +- app/src/main/res/values-ru/strings.xml | 2 +- app/src/main/res/values-tr/strings.xml | 2 +- app/src/main/res/values-uk/strings.xml | 3 ++- app/src/main/res/values-vi/strings.xml | 2 +- app/src/main/res/values-zh-rCN/strings.xml | 2 +- app/src/main/res/values-zh-rHK/strings.xml | 2 +- app/src/main/res/values-zh-rHN/strings.xml | 2 +- app/src/main/res/values-zh-rTW/strings.xml | 2 +- app/src/main/res/values/strings.xml | 2 +- .../extractcontents/PasswordProtectedRarTest.kt | 8 +++++++- gradle/libs.versions.toml | 6 +++--- 30 files changed, 47 insertions(+), 31 deletions(-) diff --git a/app/src/fdroid/java/com/github/junrar/exception/UnsupportedRarVersionException.java b/app/src/fdroid/java/com/github/junrar/exception/UnsupportedRarVersionException.java index 789412c242..61d9516c3a 100644 --- a/app/src/fdroid/java/com/github/junrar/exception/UnsupportedRarVersionException.java +++ b/app/src/fdroid/java/com/github/junrar/exception/UnsupportedRarVersionException.java @@ -20,6 +20,14 @@ package com.github.junrar.exception; +/* + * This file is extracted from junrar library (https://github.com/junrar/junrar). + * The file exist to comply with F-Droid's requirement that no proprietary archive formats can be + * supported. + * + * - TranceLove + */ + /** * Thrown when the archive signature names a RAR format this library cannot read: a future format * version byte ({@code 0x02}..{@code 0x04}) that the library predates (unrar {@code RARFMT_FUTURE}, diff --git a/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/compress/ZipHelperCallable.kt b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/compress/ZipHelperCallable.kt index f3787bdeef..5cc5265887 100644 --- a/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/compress/ZipHelperCallable.kt +++ b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/compress/ZipHelperCallable.kt @@ -51,7 +51,7 @@ class ZipHelperCallable( fileLocation.path?.run { val zipfile = ZipFile(fileLocation.path) if (!zipfile.isValidZipFile || zipfile.file.length() == 0L) { - throw ZipException("Zero byte or corrupt zip file") + throw ArchiveException("Zero byte or corrupt zip file") } val wholelist = filterValidEntryList(zipfile) val strings = ArrayList() @@ -110,7 +110,7 @@ class ZipHelperCallable( strings.add(y) } } else if (y.startsWith("$relativeDirectory/") && - y.length > relativeDirectory.length + 1 + (y.length > (relativeDirectory.length + 1)) ) { val path1 = y.substring(relativeDirectory.length + 1, y.length) val index = relativeDirectory.length + 1 + path1.indexOf("/") diff --git a/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/movecopy/PreparePasteTask.kt b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/movecopy/PreparePasteTask.kt index 7c37a24b8a..765d8123e3 100755 --- a/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/movecopy/PreparePasteTask.kt +++ b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/movecopy/PreparePasteTask.kt @@ -29,7 +29,6 @@ import com.afollestad.materialdialogs.DialogAction import com.afollestad.materialdialogs.MaterialDialog import com.amaze.filemanager.R import com.amaze.filemanager.asynchronous.asynctasks.fromTask -import com.amaze.filemanager.asynchronous.asynctasks.movecopy.PreparePasteTask.CopyNode import com.amaze.filemanager.asynchronous.management.ServiceWatcherUtil import com.amaze.filemanager.asynchronous.services.CopyService import com.amaze.filemanager.databinding.CopyDialogBinding @@ -63,6 +62,7 @@ import java.util.LinkedList * is a directory, the conflicts are resolved by inserting a node in [CopyNode] tree and then doing * BFS on this tree. */ +@Suppress("LabeledExpression") class PreparePasteTask(strongRefMain: MainActivity) { private lateinit var targetPath: String private var isMove = false diff --git a/app/src/main/java/com/amaze/filemanager/asynchronous/services/ExtractService.java b/app/src/main/java/com/amaze/filemanager/asynchronous/services/ExtractService.java index b48a9d44f9..30e3732616 100644 --- a/app/src/main/java/com/amaze/filemanager/asynchronous/services/ExtractService.java +++ b/app/src/main/java/com/amaze/filemanager/asynchronous/services/ExtractService.java @@ -368,7 +368,7 @@ public boolean isCancelled() { LOG.error(compressedPath + " is an unsupported RAR archive", e); AppConfig.toast( getApplicationContext(), - extractService.getString(R.string.error_unsupported_v5_rar, compressedPath)); + extractService.getString(R.string.error_unsupported_rar_version, compressedPath)); return false; } else { LOG.error("Error while extracting file " + compressedPath, e); diff --git a/app/src/main/java/com/amaze/filemanager/ui/fragments/CompressedExplorerFragment.kt b/app/src/main/java/com/amaze/filemanager/ui/fragments/CompressedExplorerFragment.kt index d70d9fa02b..a1fb892876 100644 --- a/app/src/main/java/com/amaze/filemanager/ui/fragments/CompressedExplorerFragment.kt +++ b/app/src/main/java/com/amaze/filemanager/ui/fragments/CompressedExplorerFragment.kt @@ -660,7 +660,7 @@ class CompressedExplorerFragment : Fragment(), BottomBarButtonPath { e?.cause?.javaClass, ) ) { - R.string.error_unsupported_v5_rar + R.string.error_unsupported_rar_version } else { R.string.archive_unsupported_or_corrupt } diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index b9bd40287e..2517883f3d 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -635,7 +635,7 @@ امكانية توصل للقراءة فقط استخدام كشف التركة للدليل الرئيسي اذا تم اتاحته ، استخدم الطريقة المتوارثة لعرض الملفات - ملف تخزين RAR \" %s \" لا يتم دعم أرشيف RAR v5. + ملف تخزين RAR \" %s \" لا يتم دعم أرشيف RAR v5. سيكون من الضروري اعادة بدء وحدة خدمة FTP لكي تصبح التغييرات فعالة. تم رفض التصريح كلمة سرية أرشيف غير صحيحة. diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 0c68b905e5..62a42990d8 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -650,7 +650,7 @@ Přístup pouze pro čtení Použít starší výpis souborů pro root Pokud je povoleno, používá k výpisu souborů starší metodu - RAR archív \"%s\" je nepodporovaný RAR v5 archív. + RAR archív \"%s\" je nepodporovaný RAR v5 archív. Budete muset FTP server restartovat pro projevení změn. Oprávněění odmítnuto Nesprávné heslo archívu. diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 9647b78e83..3daae890e3 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -659,7 +659,7 @@ andernfalls wird nach Treffern gesucht. Nur-Lesen Zugriff Alte Auflistung für Root verwenden Wenn aktiviert, wird die Legacy-Methode für die Auflistung von Dateien verwendet - RAR-Archiv \"%s\" ist ein nicht unterstütztes RAR v5-Archiv. + RAR-Archiv \"%s\" ist ein nicht unterstütztes RAR v5-Archiv. Sie müssen den FTP-Server neu starten, damit die Änderungen angewendet werden. Berechtigung verweigert Falsches Archiv-Passwort. diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 008ba75afa..760e3c55f2 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -654,7 +654,7 @@ Πρόσβαση μόνο για ανάγνωση Χρήση παλαιού καταλόγου για root Εάν είναι ενεργή, χρησιμοποιεί την παλαιά μέθοδο για τη λίστα αρχείων - Το αρχείο RAR \"%s\" είναι μη υποστηριζόμενο αρχείο RAR v5. + Το αρχείο RAR \"%s\" είναι μη υποστηριζόμενο αρχείο RAR v5. Θα χρειαστεί να επανεκκινήσετε το διακομιστή FTP για να τεθούν σε ισχύ οι αλλαγές. Απορριφθείσα άδεια Λάθος κωδικός πρόσβασης αρχείου. diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 88dd8466a3..121f46c7df 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -634,5 +634,6 @@ Solo necesita hacer esto una vez, hasta la siguiente vez que seleccione una nuev Archivos accedidos recientemente usando Amaze Archivos creados o modificados recientemente No se encontró un navegador disponible + El archivo RAR \"%s\" es un tipo de archivo RAR no compatible. diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 715e61a756..893d8308e8 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -653,7 +653,7 @@ Accès en lecture seule Utiliser l\'ancien affichage pour root Si cette option est activée, l\'ancienne méthode est utilisée pour lister les fichiers. - L\'archive RAR \"%s\" est une archive RAR v5 non prise en charge. + L\'archive RAR \"%s\" est une archive RAR v5 non prise en charge. Vous devrez redémarrer le serveur FTP pour appliquer les changements. Permission refusée Mot de passe erroné diff --git a/app/src/main/res/values-he/strings.xml b/app/src/main/res/values-he/strings.xml index 61f74a4ec7..ddcead65d0 100644 --- a/app/src/main/res/values-he/strings.xml +++ b/app/src/main/res/values-he/strings.xml @@ -708,7 +708,7 @@ גישה לקריאה בלבד להשתמש בתצוגה מיושנת למשתמש על (root) אם פעיל, ייעשה שימוש בשיטה מיושנת להצגת קבצים - ארכיון ה־RAR ‏„%s” הוא ארכיון RAR v5 שאינו נתמך. + ארכיון ה־RAR ‏„%s” הוא ארכיון RAR v5 שאינו נתמך. יהיה עליך להפעיל את שרת ה־FTP מחדש כדי שהשינויים ייכנסו לתוקף. ההרשאה נדחתה סיסמת הארכיון שגויה. diff --git a/app/src/main/res/values-hu-rHU/strings.xml b/app/src/main/res/values-hu-rHU/strings.xml index 3be818d478..75c8c0ce00 100644 --- a/app/src/main/res/values-hu-rHU/strings.xml +++ b/app/src/main/res/values-hu-rHU/strings.xml @@ -658,7 +658,7 @@ Csak olvasási hozzáférés Örökölt lista használata a gyökérhez Ha engedélyezve van, az örökölt módszer lesz használva a fájlok listázására - A(z) \"%s\" RAR egy nem támogatott RAR V5 archívum. + A(z) \"%s\" RAR egy nem támogatott RAR V5 archívum. A módosítások érvénybe léptetéséhez újra kell indítania az FTP-kiszolgálót. Hozzáférés megtagadva Rossz archívum jelszó. diff --git a/app/src/main/res/values-id/strings.xml b/app/src/main/res/values-id/strings.xml index 5fbcaf17e0..5df8a1b72b 100644 --- a/app/src/main/res/values-id/strings.xml +++ b/app/src/main/res/values-id/strings.xml @@ -652,7 +652,7 @@ Akses baca-saja Gunakan tampilan lama untuk root Jika diaktifkan, gunakan metode lama untuk menampilkan berkas - Arsip RAR \"%s\" adalah arsip RAR v5 yang tidak didukung. + Arsip RAR \"%s\" adalah arsip RAR yang tidak didukung. Anda perlu memulai ulang server FTP agar perubahan terdampak. Perizinan ditolak Sandi arsip salah. diff --git a/app/src/main/res/values-it-rIT/strings.xml b/app/src/main/res/values-it-rIT/strings.xml index 73a9bc7089..26113ec98d 100644 --- a/app/src/main/res/values-it-rIT/strings.xml +++ b/app/src/main/res/values-it-rIT/strings.xml @@ -661,7 +661,7 @@ altrimenti verrà controllata solo l\'occorrenza. Accesso di sola lettura Usa elenco legacy per root Se attivo, usa il metodo legacy per l\'elenco dei file - L\'archivio RAR \"%s\" non è un archivio RAR v5 supportato. + L\'archivio RAR \"%s\" non è un archivio RAR v5 supportato. Devi riavviare il server FTP affinché le modifiche abbiano effetto. Permesso negato Password archivio sbagliata. diff --git a/app/src/main/res/values-my/strings.xml b/app/src/main/res/values-my/strings.xml index 1fce768cd6..05fd3ce2ec 100644 --- a/app/src/main/res/values-my/strings.xml +++ b/app/src/main/res/values-my/strings.xml @@ -653,7 +653,7 @@ Read-only access Use legacy listing for root If enabled, uses legacy method to list files - RAR archive \"%s\" is unsupported RAR v5 archive. + RAR archive \"%s\" is unsupported RAR archive. You will need to restart the FTP server for changes to take effect. Permission denied Wrong archive password. diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 6fcc304b60..366da96be6 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -644,7 +644,7 @@ Dostęp tylko do odczytu Użyj starszej listy dla root Jeśli ta opcja jest włączona, używa starszej metody do wyświetlania listy plików - Archiwum RAR „%s” jest nieobsługiwanym archiwum RAR v5. + Archiwum RAR „%s” jest nieobsługiwanym archiwum RAR v5. Będziesz musiał ponownie uruchomić serwer FTP, aby zmiany zaczęły obowiązywać. Odmowa zezwolenia Nieprawidłowe hasło do archiwum. diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index f77620244d..9459bab7b1 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -653,7 +653,7 @@ Apenas leitura Usar listagem legada para root Se habilitado, usa método legado para listar arquivos - Arquivo RAR \"%s\" é um arquivo RAR v5 não suportado. + Arquivo RAR \"%s\" é um arquivo RAR v5 não suportado. Você precisa reiniciar o servidor FTP para aplicar as mudanças. Permissão negada Senha incorreta do arquivo. diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index d3712ca1bd..f01787c8c1 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -653,7 +653,7 @@ Se inativa, será procurada qualquer correspondência. Apenas leitura Usar listagem legada para root Se habilitado, usa método legado para listar arquivos - Arquivo RAR \"%s\" é um arquivo RAR v5 não suportado. + Arquivo RAR \"%s\" é um arquivo RAR v5 não suportado. Você precisa reiniciar o servidor FTP para aplicar as mudanças. Permissão negada Senha incorreta do arquivo. diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 9d52f3504a..0b02a58f16 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -641,7 +641,7 @@ Доступ только для чтения Использовать устаревший вид список для root Если включить, будет использоваться устаревший метод для вывода списка файлов - Архив RAR \"%s\" не поддерживается архивом RAR v5. + Архив RAR \"%s\" не поддерживается архивом RAR v5. Чтобы изменения вступили в силу, вам нужно будет перезапустить FTP-сервер. В доступе отказано Неверный пароль архива. diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index b06d6219ce..441ce1692e 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -657,7 +657,7 @@ Ana bilgisayar parmak izini güncellemeye devam edebilir veya SSH bağlantı aya Salt okunur erişim Root için eski listeyi kullan Etkinleştirilirse, dosyaları listelemek için eski yöntemi kullanır - \"%s\" RAR arşivi desteklenmeyen RAR v5 arşividir. + \"%s\" RAR arşivi desteklenmeyen RAR v5 arşividir. Değişikliklerin etkili olması için FTP sunucusunu yeniden başlatmanız gerekecek. İzin reddedildi Yanlış arşiv şifresi. diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index 762cec223c..c748e7398a 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -606,5 +606,6 @@ Дозвіл відмовлено Не вірний пароль архіву. Вимкнено - + Архів RAR \"%s\" є архіву RAR, який не підтримується + diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index 90d3984a9c..52568d1f06 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -637,7 +637,7 @@ Truy cập chỉ đọc Sử dụng danh sách cũ cho root Nếu được bật, sẽ sử dụng phương pháp cũ để liệt kê các tệp - Lưu trữ RAR \"%s\" là lưu trữ RAR v5 không được hỗ trợ. + Lưu trữ RAR \"%s\" là lưu trữ RAR v5 không được hỗ trợ. Bạn sẽ cần khởi động lại máy chủ FTP để các thay đổi có hiệu lực. Quyền bị từ chối Mật khẩu lưu trữ sai. diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 37065f0f7b..0d8f7513f3 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -666,7 +666,7 @@ 只读访问权限 对根目录使用传统的文件列表方式 启用后,将使用传统方法列出文件 - 尚不支持RAR 压缩文件\"%s\",因为它是最新的第5版RAR格式。 + 尚不支持RAR 压缩文件\"%s\",因为它是最新的第5版RAR格式。 需要您重启文件传输协议服务器,使得新设定生效 拒绝许可 解压密码有误 diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index 49a150a5ea..ba1dcf480c 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -651,7 +651,7 @@ 唯讀模式 喺 Root模式使用舊有方式列出文件 開啟呢個設定嘅話,Amaze會用番原有嘅方法列出文件 - RAR 壓縮檔 \"%s\" 係未能支援嘅 RAR v5壓縮檔。 + RAR 壓縮檔 \"%s\" 係未能支援嘅 RAR壓縮檔。 要使設定生效,請重新啟動 FTP伺服器 拒絕存取 壓縮檔嘅密碼錯咗。 diff --git a/app/src/main/res/values-zh-rHN/strings.xml b/app/src/main/res/values-zh-rHN/strings.xml index 6702cd0a41..8c8cd75084 100644 --- a/app/src/main/res/values-zh-rHN/strings.xml +++ b/app/src/main/res/values-zh-rHN/strings.xml @@ -651,7 +651,7 @@ 唯讀模式 喺 Root模式使用舊有方式列出文件 開啟呢個設定嘅話,Amaze會用番原有嘅方法列出文件 - RAR 压缩文件\"%s\"是尚未支持的RAR v5 文件。 + RAR 压缩文件\"%s\"是尚未支持的 RAR文件。 要使設定生效,請重新啟動 FTP伺服器 权限不足 解压密码有误 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index b26a193a7c..144d702bff 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -651,7 +651,7 @@ 唯讀存取 在 Root模式使用舊有方式列出文件 開啟此設定的話,Amaze會使用原有的方法列出文件 - RAR 壓縮檔 \"%s\" 是未能支援的 RAR v5壓縮檔。 + RAR 壓縮檔 \"%s\" 是未能支援的 RAR壓縮檔。 請重新啟動 FTP伺服器以套用新設定。 拒絕存取 錯誤的壓縮檔密碼。 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e6bcdb1595..056dd7afd1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -738,7 +738,7 @@ Read-only access Use legacy listing for root If enabled, uses legacy method to list files - RAR archive \"%s\" is unsupported RAR v5 archive. + RAR archive \"%s\" is an unsupported RAR archive. You will need to restart the FTP server for changes to take effect. Permission denied Wrong archive password. diff --git a/app/src/testPlay/java/com/amaze/filemanager/filesystem/compressed/extractcontents/PasswordProtectedRarTest.kt b/app/src/testPlay/java/com/amaze/filemanager/filesystem/compressed/extractcontents/PasswordProtectedRarTest.kt index bc43af985a..f4251c53db 100644 --- a/app/src/testPlay/java/com/amaze/filemanager/filesystem/compressed/extractcontents/PasswordProtectedRarTest.kt +++ b/app/src/testPlay/java/com/amaze/filemanager/filesystem/compressed/extractcontents/PasswordProtectedRarTest.kt @@ -21,6 +21,7 @@ package com.amaze.filemanager.filesystem.compressed.extractcontents import com.amaze.filemanager.filesystem.compressed.extractcontents.helpers.RarExtractor +import com.github.junrar.exception.BadRarArchiveException import org.apache.commons.compress.PasswordRequiredException import org.junit.Ignore import org.junit.Test @@ -29,7 +30,12 @@ import java.io.IOException open class PasswordProtectedRarTest : AbstractExtractorPasswordProtectedArchivesTest() { override fun extractorClass(): Class = RarExtractor::class.java - override fun expectedRootExceptionClass(): Array> = arrayOf(IOException::class.java, PasswordRequiredException::class.java) + override fun expectedRootExceptionClass(): Array> = + arrayOf( + IOException::class.java, + PasswordRequiredException::class.java, + BadRarArchiveException::class.java, + ) override val archiveType: String = "rar" diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index e36c9650f3..015ac5b1f5 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -42,7 +42,7 @@ kotlinxCoroutineTest = "1.11.0" kotlinStdlibJdk8 = "2.2.10" uiAutomator = "2.3.0" junit = "4.13.2" -slf4j = "2.0.18" +slf4j = "2.0.19" apacheSshd = "2.19.0" apacheMina = "2.2.9" mockito = "5.23.0" @@ -50,7 +50,7 @@ mockitoInline = "5.2.0" mockitoKotlin = "6.3.0" androidBilling = "9.1.0" cloudrailSiAndroid = "2.22.4" -junrar = "8.1.0" +junrar = "8.1.1" vectordrawableAnimated = "1.2.0" xz = "1.12" zip4j = "2.11.6" @@ -64,7 +64,7 @@ logbackAndroid = "3.0.0" logbackClassic = "1.6.1" commonsNet = "3.13.0" ftpserver = "1.2.1" -jsoup = "1.23.1" +jsoup = "1.23.2" gson = "2.14.0" rxAndroid = "2.1.1" rxJava = "2.2.21" From 774b8dcc9ee5b4dd03cf654a89aba3462a38ff72 Mon Sep 17 00:00:00 2001 From: Raymond Lai Date: Mon, 7 Sep 2026 00:08:32 +0800 Subject: [PATCH 7/8] Changes per PR feedback - Refactorings to ZipHelperCallable for better exception logic --- .../asynctasks/compress/ZipHelperCallable.kt | 143 +++++++++--------- 1 file changed, 73 insertions(+), 70 deletions(-) diff --git a/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/compress/ZipHelperCallable.kt b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/compress/ZipHelperCallable.kt index 5cc5265887..ed44b616bc 100644 --- a/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/compress/ZipHelperCallable.kt +++ b/app/src/main/java/com/amaze/filemanager/asynchronous/asynctasks/compress/ZipHelperCallable.kt @@ -22,6 +22,7 @@ package com.amaze.filemanager.asynchronous.asynctasks.compress import android.content.Context import android.net.Uri +import androidx.core.net.toUri import com.amaze.filemanager.R import com.amaze.filemanager.adapters.data.CompressedObjectParcelable import com.amaze.filemanager.application.AppConfig @@ -41,98 +42,100 @@ class ZipHelperCallable( ) : CompressedHelperCallable(goback) { private val context: WeakReference = WeakReference(c) - private val fileLocation: Uri = Uri.parse(realFileDirectory) + private val fileLocation: Uri = realFileDirectory.toUri() private val relativeDirectory: String? = dir @Throws(ArchiveException::class) @Suppress("ComplexMethod", "LongMethod") - public override fun addElements(elements: ArrayList) = + public override fun addElements(elements: ArrayList) { + val path = + fileLocation.path + ?: throw ArchiveException("Invalid zip file location: $fileLocation") try { - fileLocation.path?.run { - val zipfile = ZipFile(fileLocation.path) - if (!zipfile.isValidZipFile || zipfile.file.length() == 0L) { - throw ArchiveException("Zero byte or corrupt zip file") - } - val wholelist = filterValidEntryList(zipfile) - val strings = ArrayList() - for (entry in wholelist) { - val file = File(entry.path) - val y = - entry.path.let { - if (it.startsWith("/")) { - it.substring(1, it.length) - } else { - it - } + val zipfile = ZipFile(path) + if (!zipfile.isValidZipFile || zipfile.file.length() == 0L) { + throw ZipException("Zero byte or corrupt zip file") + } + val wholelist = filterValidEntryList(zipfile) + val strings = ArrayList() + for (entry in wholelist) { + val file = File(entry.path) + val y = + entry.path.let { + if (it.startsWith("/")) { + it.substring(1, it.length) + } else { + it } - if (relativeDirectory == null || relativeDirectory.trim { it <= ' ' }.isEmpty()) { - var path: String - var zipObj: CompressedObjectParcelable - if (file.parent == null || file.parent!!.isEmpty() || file.parent == "/") { - path = y - zipObj = + } + if (relativeDirectory == null || relativeDirectory.trim { it <= ' ' }.isEmpty()) { + var path: String + var zipObj: CompressedObjectParcelable + if (file.parent == null || file.parent!!.isEmpty() || file.parent == "/") { + path = y + zipObj = + CompressedObjectParcelable( + y, + entry.date, + entry.size, + entry.directory, + ) + } else { + path = y.substring(0, y.indexOf("/") + 1) + zipObj = + CompressedObjectParcelable( + path, + entry.date, + entry.size, + true, + ) + } + if (!strings.contains(path)) { + elements.add(zipObj) + strings.add(path) + } + } else { + if (file.parent != null && + ( + file.parent == relativeDirectory || + file.parent == "/$relativeDirectory" + ) + ) { + if (!strings.contains(y)) { + elements.add( CompressedObjectParcelable( y, entry.date, entry.size, entry.directory, - ) - } else { - path = y.substring(0, y.indexOf("/") + 1) - zipObj = + ), + ) + strings.add(y) + } + } else if (y.startsWith("$relativeDirectory/") && + (y.length > (relativeDirectory.length + 1)) + ) { + val path1 = y.substring(relativeDirectory.length + 1, y.length) + val index = relativeDirectory.length + 1 + path1.indexOf("/") + val path = y.substring(0, index + 1) + if (!strings.contains(path)) { + elements.add( CompressedObjectParcelable( - path, + y.substring(0, index + 1), entry.date, entry.size, true, - ) - } - if (!strings.contains(path)) { - elements.add(zipObj) - strings.add(path) - } - } else { - if (file.parent != null && - ( - file.parent == relativeDirectory || - file.parent == "/$relativeDirectory" + ), ) - ) { - if (!strings.contains(y)) { - elements.add( - CompressedObjectParcelable( - y, - entry.date, - entry.size, - entry.directory, - ), - ) - strings.add(y) - } - } else if (y.startsWith("$relativeDirectory/") && - (y.length > (relativeDirectory.length + 1)) - ) { - val path1 = y.substring(relativeDirectory.length + 1, y.length) - val index = relativeDirectory.length + 1 + path1.indexOf("/") - val path = y.substring(0, index + 1) - if (!strings.contains(path)) { - elements.add( - CompressedObjectParcelable( - y.substring(0, index + 1), - entry.date, - entry.size, - true, - ), - ) - strings.add(path) - } + strings.add(path) } } } - } ?: throw ArchiveException(null) + } } catch (e: ZipException) { throw ArchiveException("Zip file is corrupt", e) } + } private fun filterValidEntryList(zipFile: ZipFile): List { val retval = ArrayList() From 55b2734bf15adb53aa9b89b32e23f94c44157cf1 Mon Sep 17 00:00:00 2001 From: TranceLove Date: Tue, 15 Sep 2026 14:30:09 +0900 Subject: [PATCH 8/8] Changes per PR feedback Remove string resource error_unsupported_v5_rar with error_unsupported_rar --- .../ftp/FtpServerSslKeyStoreProvider.kt | 20 +++++++++++++++++++ app/src/main/res/values-ar/strings.xml | 1 - app/src/main/res/values-cs/strings.xml | 1 - app/src/main/res/values-de/strings.xml | 1 - app/src/main/res/values-el/strings.xml | 1 - app/src/main/res/values-es/strings.xml | 2 +- app/src/main/res/values-fr/strings.xml | 1 - app/src/main/res/values-he/strings.xml | 1 - app/src/main/res/values-hu-rHU/strings.xml | 1 - app/src/main/res/values-id/strings.xml | 1 - app/src/main/res/values-it-rIT/strings.xml | 1 - app/src/main/res/values-pl/strings.xml | 1 - app/src/main/res/values-pt-rBR/strings.xml | 1 - app/src/main/res/values-pt-rPT/strings.xml | 1 - app/src/main/res/values-ru/strings.xml | 1 - app/src/main/res/values-tr/strings.xml | 1 - app/src/main/res/values-uk/strings.xml | 2 +- app/src/main/res/values-vi/strings.xml | 1 - app/src/main/res/values-zh-rCN/strings.xml | 2 +- app/src/main/res/values-zh-rHN/strings.xml | 1 - 20 files changed, 23 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/com/amaze/filemanager/asynchronous/services/ftp/FtpServerSslKeyStoreProvider.kt b/app/src/main/java/com/amaze/filemanager/asynchronous/services/ftp/FtpServerSslKeyStoreProvider.kt index b0601fe983..dcb79e1f75 100644 --- a/app/src/main/java/com/amaze/filemanager/asynchronous/services/ftp/FtpServerSslKeyStoreProvider.kt +++ b/app/src/main/java/com/amaze/filemanager/asynchronous/services/ftp/FtpServerSslKeyStoreProvider.kt @@ -1,3 +1,23 @@ +/* + * Copyright (C) 2014-2026 Arpit Khurana , Vishal Nehra , + * Emmanuel Messulam, Raymond Lai and Contributors. + * + * This file is part of Amaze File Manager. + * + * Amaze File Manager is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + package com.amaze.filemanager.asynchronous.services.ftp import android.annotation.SuppressLint diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 2517883f3d..2043bbcd82 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -635,7 +635,6 @@ امكانية توصل للقراءة فقط استخدام كشف التركة للدليل الرئيسي اذا تم اتاحته ، استخدم الطريقة المتوارثة لعرض الملفات - ملف تخزين RAR \" %s \" لا يتم دعم أرشيف RAR v5. سيكون من الضروري اعادة بدء وحدة خدمة FTP لكي تصبح التغييرات فعالة. تم رفض التصريح كلمة سرية أرشيف غير صحيحة. diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml index 62a42990d8..3017555ab8 100644 --- a/app/src/main/res/values-cs/strings.xml +++ b/app/src/main/res/values-cs/strings.xml @@ -650,7 +650,6 @@ Přístup pouze pro čtení Použít starší výpis souborů pro root Pokud je povoleno, používá k výpisu souborů starší metodu - RAR archív \"%s\" je nepodporovaný RAR v5 archív. Budete muset FTP server restartovat pro projevení změn. Oprávněění odmítnuto Nesprávné heslo archívu. diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 3daae890e3..e7179dd5a5 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -659,7 +659,6 @@ andernfalls wird nach Treffern gesucht. Nur-Lesen Zugriff Alte Auflistung für Root verwenden Wenn aktiviert, wird die Legacy-Methode für die Auflistung von Dateien verwendet - RAR-Archiv \"%s\" ist ein nicht unterstütztes RAR v5-Archiv. Sie müssen den FTP-Server neu starten, damit die Änderungen angewendet werden. Berechtigung verweigert Falsches Archiv-Passwort. diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml index 760e3c55f2..5297fa3082 100644 --- a/app/src/main/res/values-el/strings.xml +++ b/app/src/main/res/values-el/strings.xml @@ -654,7 +654,6 @@ Πρόσβαση μόνο για ανάγνωση Χρήση παλαιού καταλόγου για root Εάν είναι ενεργή, χρησιμοποιεί την παλαιά μέθοδο για τη λίστα αρχείων - Το αρχείο RAR \"%s\" είναι μη υποστηριζόμενο αρχείο RAR v5. Θα χρειαστεί να επανεκκινήσετε το διακομιστή FTP για να τεθούν σε ισχύ οι αλλαγές. Απορριφθείσα άδεια Λάθος κωδικός πρόσβασης αρχείου. diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 121f46c7df..29422d69ab 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -634,6 +634,6 @@ Solo necesita hacer esto una vez, hasta la siguiente vez que seleccione una nuev Archivos accedidos recientemente usando Amaze Archivos creados o modificados recientemente No se encontró un navegador disponible - El archivo RAR \"%s\" es un tipo de archivo RAR no compatible. + El archivo RAR \"%s\" es un archivo RAR no compatible. diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 893d8308e8..f6d72f064c 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -653,7 +653,6 @@ Accès en lecture seule Utiliser l\'ancien affichage pour root Si cette option est activée, l\'ancienne méthode est utilisée pour lister les fichiers. - L\'archive RAR \"%s\" est une archive RAR v5 non prise en charge. Vous devrez redémarrer le serveur FTP pour appliquer les changements. Permission refusée Mot de passe erroné diff --git a/app/src/main/res/values-he/strings.xml b/app/src/main/res/values-he/strings.xml index ddcead65d0..6e939d2073 100644 --- a/app/src/main/res/values-he/strings.xml +++ b/app/src/main/res/values-he/strings.xml @@ -708,7 +708,6 @@ גישה לקריאה בלבד להשתמש בתצוגה מיושנת למשתמש על (root) אם פעיל, ייעשה שימוש בשיטה מיושנת להצגת קבצים - ארכיון ה־RAR ‏„%s” הוא ארכיון RAR v5 שאינו נתמך. יהיה עליך להפעיל את שרת ה־FTP מחדש כדי שהשינויים ייכנסו לתוקף. ההרשאה נדחתה סיסמת הארכיון שגויה. diff --git a/app/src/main/res/values-hu-rHU/strings.xml b/app/src/main/res/values-hu-rHU/strings.xml index 75c8c0ce00..1389f8b49b 100644 --- a/app/src/main/res/values-hu-rHU/strings.xml +++ b/app/src/main/res/values-hu-rHU/strings.xml @@ -658,7 +658,6 @@ Csak olvasási hozzáférés Örökölt lista használata a gyökérhez Ha engedélyezve van, az örökölt módszer lesz használva a fájlok listázására - A(z) \"%s\" RAR egy nem támogatott RAR V5 archívum. A módosítások érvénybe léptetéséhez újra kell indítania az FTP-kiszolgálót. Hozzáférés megtagadva Rossz archívum jelszó. diff --git a/app/src/main/res/values-id/strings.xml b/app/src/main/res/values-id/strings.xml index 5df8a1b72b..74ebbefe58 100644 --- a/app/src/main/res/values-id/strings.xml +++ b/app/src/main/res/values-id/strings.xml @@ -652,7 +652,6 @@ Akses baca-saja Gunakan tampilan lama untuk root Jika diaktifkan, gunakan metode lama untuk menampilkan berkas - Arsip RAR \"%s\" adalah arsip RAR yang tidak didukung. Anda perlu memulai ulang server FTP agar perubahan terdampak. Perizinan ditolak Sandi arsip salah. diff --git a/app/src/main/res/values-it-rIT/strings.xml b/app/src/main/res/values-it-rIT/strings.xml index 26113ec98d..d889a645cb 100644 --- a/app/src/main/res/values-it-rIT/strings.xml +++ b/app/src/main/res/values-it-rIT/strings.xml @@ -661,7 +661,6 @@ altrimenti verrà controllata solo l\'occorrenza. Accesso di sola lettura Usa elenco legacy per root Se attivo, usa il metodo legacy per l\'elenco dei file - L\'archivio RAR \"%s\" non è un archivio RAR v5 supportato. Devi riavviare il server FTP affinché le modifiche abbiano effetto. Permesso negato Password archivio sbagliata. diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 366da96be6..31719397e7 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -644,7 +644,6 @@ Dostęp tylko do odczytu Użyj starszej listy dla root Jeśli ta opcja jest włączona, używa starszej metody do wyświetlania listy plików - Archiwum RAR „%s” jest nieobsługiwanym archiwum RAR v5. Będziesz musiał ponownie uruchomić serwer FTP, aby zmiany zaczęły obowiązywać. Odmowa zezwolenia Nieprawidłowe hasło do archiwum. diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 9459bab7b1..f3cdd3594b 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -653,7 +653,6 @@ Apenas leitura Usar listagem legada para root Se habilitado, usa método legado para listar arquivos - Arquivo RAR \"%s\" é um arquivo RAR v5 não suportado. Você precisa reiniciar o servidor FTP para aplicar as mudanças. Permissão negada Senha incorreta do arquivo. diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index f01787c8c1..e715b91a91 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -653,7 +653,6 @@ Se inativa, será procurada qualquer correspondência. Apenas leitura Usar listagem legada para root Se habilitado, usa método legado para listar arquivos - Arquivo RAR \"%s\" é um arquivo RAR v5 não suportado. Você precisa reiniciar o servidor FTP para aplicar as mudanças. Permissão negada Senha incorreta do arquivo. diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 0b02a58f16..87f850e272 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -641,7 +641,6 @@ Доступ только для чтения Использовать устаревший вид список для root Если включить, будет использоваться устаревший метод для вывода списка файлов - Архив RAR \"%s\" не поддерживается архивом RAR v5. Чтобы изменения вступили в силу, вам нужно будет перезапустить FTP-сервер. В доступе отказано Неверный пароль архива. diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 441ce1692e..5fd225aeec 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -657,7 +657,6 @@ Ana bilgisayar parmak izini güncellemeye devam edebilir veya SSH bağlantı aya Salt okunur erişim Root için eski listeyi kullan Etkinleştirilirse, dosyaları listelemek için eski yöntemi kullanır - \"%s\" RAR arşivi desteklenmeyen RAR v5 arşividir. Değişikliklerin etkili olması için FTP sunucusunu yeniden başlatmanız gerekecek. İzin reddedildi Yanlış arşiv şifresi. diff --git a/app/src/main/res/values-uk/strings.xml b/app/src/main/res/values-uk/strings.xml index c748e7398a..0f4a20e9a5 100644 --- a/app/src/main/res/values-uk/strings.xml +++ b/app/src/main/res/values-uk/strings.xml @@ -603,9 +603,9 @@ Очистити кеш Очищає вибрані програми відкриття файлів за замовчуванням Використовуйте застарілий список для root + Архів RAR \"%s\" є архівом RAR, який не підтримується. Дозвіл відмовлено Не вірний пароль архіву. Вимкнено - Архів RAR \"%s\" є архіву RAR, який не підтримується diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml index 52568d1f06..0b208714c2 100644 --- a/app/src/main/res/values-vi/strings.xml +++ b/app/src/main/res/values-vi/strings.xml @@ -637,7 +637,6 @@ Truy cập chỉ đọc Sử dụng danh sách cũ cho root Nếu được bật, sẽ sử dụng phương pháp cũ để liệt kê các tệp - Lưu trữ RAR \"%s\" là lưu trữ RAR v5 không được hỗ trợ. Bạn sẽ cần khởi động lại máy chủ FTP để các thay đổi có hiệu lực. Quyền bị từ chối Mật khẩu lưu trữ sai. diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 0d8f7513f3..112c5b4723 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -666,7 +666,7 @@ 只读访问权限 对根目录使用传统的文件列表方式 启用后,将使用传统方法列出文件 - 尚不支持RAR 压缩文件\"%s\",因为它是最新的第5版RAR格式。 + 尚不支持RAR 压缩文件\"%s\",因为它是最新的 RAR格式。 需要您重启文件传输协议服务器,使得新设定生效 拒绝许可 解压密码有误 diff --git a/app/src/main/res/values-zh-rHN/strings.xml b/app/src/main/res/values-zh-rHN/strings.xml index 8c8cd75084..61db2071f6 100644 --- a/app/src/main/res/values-zh-rHN/strings.xml +++ b/app/src/main/res/values-zh-rHN/strings.xml @@ -651,7 +651,6 @@ 唯讀模式 喺 Root模式使用舊有方式列出文件 開啟呢個設定嘅話,Amaze會用番原有嘅方法列出文件 - RAR 压缩文件\"%s\"是尚未支持的 RAR文件。 要使設定生效,請重新啟動 FTP伺服器 权限不足 解压密码有误