diff --git a/externals/libadrenotools b/externals/libadrenotools index 5deac9f1ab..8fae8ce254 160000 --- a/externals/libadrenotools +++ b/externals/libadrenotools @@ -1 +1 @@ -Subproject commit 5deac9f1ab2bd833ad664bc3386ac1e8998cecb3 +Subproject commit 8fae8ce254dfc1344527e05301e43f37dea2df80 diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts index d8f838cc6e..c6113d70a5 100644 --- a/src/android/app/build.gradle.kts +++ b/src/android/app/build.gradle.kts @@ -27,9 +27,9 @@ val downloadedJniLibsPath = "${buildDir}/downloadedJniLibs" @Suppress("UnstableApiUsage") android { namespace = "io.github.mandarine3ds.mandarine" + compileSdk = 35 - compileSdkVersion = "android-34" - ndkVersion = "26.3.11579264" + ndkVersion = "27.0.12077973" compileOptions { sourceCompatibility = JavaVersion.VERSION_17 @@ -63,7 +63,7 @@ android { // TODO If this is ever modified, change application_id in strings.xml applicationId = "io.github.mandarine3ds.mandarine" minSdk = 28 - targetSdk = 34 + targetSdk = 35 versionCode = autoVersion versionName = getGitVersion() @@ -77,7 +77,8 @@ android { arguments( "-DENABLE_QT=0", // Don't use QT "-DENABLE_SDL2=0", // Don't use SDL - "-DANDROID_ARM_NEON=true" // cryptopp requires Neon to work + "-DANDROID_ARM_NEON=true", // cryptopp requires Neon to work + "-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON" ) } } @@ -159,27 +160,28 @@ android { jniLibs.srcDir(downloadedJniLibsPath) } } + buildToolsVersion = "35.0.0" } dependencies { implementation("androidx.recyclerview:recyclerview:1.3.2") - implementation("androidx.activity:activity-ktx:1.8.2") - implementation("androidx.fragment:fragment-ktx:1.7.1") - implementation("androidx.appcompat:appcompat:1.6.1") + implementation("androidx.activity:activity-ktx:1.9.2") + implementation("androidx.fragment:fragment-ktx:1.8.3") + implementation("androidx.appcompat:appcompat:1.7.0") implementation("androidx.documentfile:documentfile:1.0.1") - implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.0") + implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.8.5") implementation("androidx.slidingpanelayout:slidingpanelayout:1.2.0") - implementation("com.google.android.material:material:1.9.0") + implementation("com.google.android.material:material:1.12.0") implementation("androidx.core:core-splashscreen:1.0.1") implementation("androidx.work:work-runtime:2.9.1") implementation("org.ini4j:ini4j:0.5.4") implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0") - implementation("androidx.navigation:navigation-fragment-ktx:2.7.7") - implementation("androidx.navigation:navigation-ui-ktx:2.7.7") + implementation("androidx.navigation:navigation-fragment-ktx:2.8.0") + implementation("androidx.navigation:navigation-ui-ktx:2.8.0") implementation("info.debatty:java-string-similarity:2.0.0") - implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3") + implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2") implementation("androidx.preference:preference-ktx:1.2.1") - implementation("io.coil-kt:coil:2.6.0") + implementation("io.coil-kt:coil:2.7.0") } // Download Vulkan Validation Layers from the KhronosGroup GitHub. diff --git a/src/android/app/src/main/java/io/github/mandarine3ds/mandarine/fragments/HomeSettingsFragment.kt b/src/android/app/src/main/java/io/github/mandarine3ds/mandarine/fragments/HomeSettingsFragment.kt index a42f2f5b50..9401b065ea 100644 --- a/src/android/app/src/main/java/io/github/mandarine3ds/mandarine/fragments/HomeSettingsFragment.kt +++ b/src/android/app/src/main/java/io/github/mandarine3ds/mandarine/fragments/HomeSettingsFragment.kt @@ -5,6 +5,7 @@ package io.github.mandarine3ds.mandarine.fragments import android.content.Intent +import android.net.Uri import android.os.Bundle import android.view.LayoutInflater import android.view.View @@ -158,7 +159,7 @@ class HomeSettingsFragment : Fragment() { R.string.select_mandarine_user_folder, R.string.select_mandarine_user_folder_home_description, R.drawable.ic_home, - { mainActivity.openMandarineDirectory.launch(null) }, + { mainActivity.openMandarineDirectory.launch(Uri.parse(null)) }, details = homeViewModel.userDir ), HomeSetting( diff --git a/src/android/app/src/main/java/io/github/mandarine3ds/mandarine/fragments/MandarineDirectoryDialogFragment.kt b/src/android/app/src/main/java/io/github/mandarine3ds/mandarine/fragments/MandarineDirectoryDialogFragment.kt index 77da4369d0..55ba0c2503 100644 --- a/src/android/app/src/main/java/io/github/mandarine3ds/mandarine/fragments/MandarineDirectoryDialogFragment.kt +++ b/src/android/app/src/main/java/io/github/mandarine3ds/mandarine/fragments/MandarineDirectoryDialogFragment.kt @@ -60,7 +60,7 @@ class MandarineDirectoryDialogFragment : DialogFragment() { } .setNegativeButton(android.R.string.cancel) { _: DialogInterface?, _: Int -> if (!PermissionsHandler.hasWriteAccess(requireContext())) { - (requireActivity() as MainActivity).openMandarineDirectory.launch(null) + (requireActivity() as MainActivity).openMandarineDirectory.launch(Uri.parse(null)) } } .show() diff --git a/src/android/app/src/main/java/io/github/mandarine3ds/mandarine/fragments/SelectUserDirectoryDialogFragment.kt b/src/android/app/src/main/java/io/github/mandarine3ds/mandarine/fragments/SelectUserDirectoryDialogFragment.kt index d03a2cfb1b..88876438a9 100644 --- a/src/android/app/src/main/java/io/github/mandarine3ds/mandarine/fragments/SelectUserDirectoryDialogFragment.kt +++ b/src/android/app/src/main/java/io/github/mandarine3ds/mandarine/fragments/SelectUserDirectoryDialogFragment.kt @@ -6,6 +6,7 @@ package io.github.mandarine3ds.mandarine.fragments import android.app.Dialog import android.content.DialogInterface +import android.net.Uri import android.os.Bundle import androidx.fragment.app.DialogFragment import androidx.fragment.app.FragmentActivity @@ -26,7 +27,7 @@ class SelectUserDirectoryDialogFragment : DialogFragment() { .setTitle(R.string.select_mandarine_user_folder) .setMessage(R.string.cannot_skip_directory_description) .setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int -> - mainActivity.openMandarineDirectory.launch(null) + mainActivity.openMandarineDirectory.launch(Uri.parse(null)) } .show() } diff --git a/src/android/app/src/main/java/io/github/mandarine3ds/mandarine/ui/main/MainActivity.kt b/src/android/app/src/main/java/io/github/mandarine3ds/mandarine/ui/main/MainActivity.kt index d1185ca005..72d6c30900 100644 --- a/src/android/app/src/main/java/io/github/mandarine3ds/mandarine/ui/main/MainActivity.kt +++ b/src/android/app/src/main/java/io/github/mandarine3ds/mandarine/ui/main/MainActivity.kt @@ -303,9 +303,7 @@ class MainActivity : AppCompatActivity(), ThemeProvider { windowInsets } - val openMandarineDirectory = registerForActivityResult( - ActivityResultContracts.OpenDocumentTree() - ) { result: Uri? -> + val openMandarineDirectory = registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { result: Uri? -> if (result == null) { return@registerForActivityResult } diff --git a/src/android/app/src/main/java/io/github/mandarine3ds/mandarine/utils/FileUtil.kt b/src/android/app/src/main/java/io/github/mandarine3ds/mandarine/utils/FileUtil.kt index 8586ab5306..72e55bb3de 100644 --- a/src/android/app/src/main/java/io/github/mandarine3ds/mandarine/utils/FileUtil.kt +++ b/src/android/app/src/main/java/io/github/mandarine3ds/mandarine/utils/FileUtil.kt @@ -16,6 +16,7 @@ import io.github.mandarine3ds.mandarine.MandarineApplication import io.github.mandarine3ds.mandarine.model.CheapDocument import java.io.BufferedInputStream import java.io.File +import java.io.FileNotFoundException import java.io.FileOutputStream import java.io.IOException import java.io.InputStream @@ -100,18 +101,21 @@ object FileUtil { @JvmStatic fun openContentUri(path: String, openMode: String): Int { try { - context - .contentResolver - .openFileDescriptor(Uri.parse(path), openMode) - .use { parcelFileDescriptor -> - if (parcelFileDescriptor == null) { - Log.error("[FileUtil]: Cannot get the file descriptor from uri: $path") - return -1 - } - return parcelFileDescriptor.detachFd() - } + val uri = Uri.parse(path) + context.contentResolver.openFileDescriptor(uri, openMode)?.use { parcelFileDescriptor -> + return parcelFileDescriptor.detachFd() + } ?: run { + Log.error("[FileUtil]: Cannot get the file descriptor from uri: $path") + return -1 + } + } catch (e: FileNotFoundException) { + Log.error("[FileUtil]: File not found for uri: $path. ${e.message}") + return -1 + } catch (e: SecurityException) { + Log.error("[FileUtil]: Security exception while accessing uri: $path, ${e.message}") + return -1 } catch (e: Exception) { - Log.error("[FileUtil]: Cannot open content uri, error: " + e.message) + Log.error("[FileUtil]: Unexpected error while opening content uri: $path. ${e.message}") return -1 } } @@ -130,8 +134,9 @@ object FileUtil { DocumentsContract.Document.COLUMN_DISPLAY_NAME, DocumentsContract.Document.COLUMN_MIME_TYPE ) - var c: Cursor? = null - val results: MutableList = ArrayList() + var cursor: Cursor? = null + val results = mutableListOf() + try { val docId = if (isRootTreeUri(uri)) { DocumentsContract.getTreeDocumentId(uri) @@ -140,21 +145,26 @@ object FileUtil { } val childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(uri, docId) - c = context.contentResolver.query(childrenUri, columns, null, null, null) - while (c!!.moveToNext()) { - val documentId = c.getString(0) - val documentName = c.getString(1) - val documentMimeType = c.getString(2) - val documentUri = DocumentsContract.buildDocumentUriUsingTree(uri, documentId) - val document = CheapDocument(documentName, documentMimeType, documentUri) - results.add(document) + cursor = context.contentResolver.query(childrenUri, columns, null, null, null) + + cursor?.use { c -> + while (c.moveToNext()) { + val documentId = c.getString(c.getColumnIndexOrThrow(DocumentsContract.Document.COLUMN_DOCUMENT_ID)) + val documentName = c.getString(c.getColumnIndexOrThrow(DocumentsContract.Document.COLUMN_DISPLAY_NAME)) + val documentMimeType = c.getString(c.getColumnIndexOrThrow(DocumentsContract.Document.COLUMN_MIME_TYPE)) + val documentUri = DocumentsContract.buildDocumentUriUsingTree(uri, documentId) + val document = CheapDocument(documentName, documentMimeType, documentUri) + results.add(document) + } + } ?: run { + Log.error("[FileUtil]: Cursor is null") } + } catch (e: Exception) { - Log.error("[FileUtil]: Cannot list file error: " + e.message) - } finally { - closeQuietly(c) + Log.error("[FileUtil]: Cannot list files: ${e.message}") } - return results.toTypedArray() + + return results.toTypedArray() } /** diff --git a/src/android/app/src/main/jni/ndk_motion.cpp b/src/android/app/src/main/jni/ndk_motion.cpp index 0f640b7cce..38b7f75bd5 100644 --- a/src/android/app/src/main/jni/ndk_motion.cpp +++ b/src/android/app/src/main/jni/ndk_motion.cpp @@ -82,7 +82,7 @@ class NDKMotion final : public Input::MotionDevice { } void Update() const { - ALooper_pollAll(0, nullptr, nullptr, nullptr); + ALooper_pollOnce(0, nullptr, nullptr, nullptr); ASensorEvent event{}; std::optional> new_accel{}, new_rot{}; while (ASensorEventQueue_getEvents(event_queue, &event, 1) > 0) { diff --git a/src/android/build.gradle.kts b/src/android/build.gradle.kts index f8f5d50d95..2da29fc893 100644 --- a/src/android/build.gradle.kts +++ b/src/android/build.gradle.kts @@ -4,7 +4,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { - id("com.android.application") version "8.5.2" apply false + id("com.android.application") version "8.6.0" apply false id("com.android.library") version "8.5.2" apply false id("org.jetbrains.kotlin.android") version "2.0.0" apply false id("org.jetbrains.kotlin.plugin.serialization") version "2.0.0" @@ -19,6 +19,6 @@ buildscript { google() } dependencies { - classpath("androidx.navigation:navigation-safe-args-gradle-plugin:2.7.7") + classpath("androidx.navigation:navigation-safe-args-gradle-plugin:2.8.0") } } diff --git a/src/android/gradle/wrapper/gradle-wrapper.properties b/src/android/gradle/wrapper/gradle-wrapper.properties index 03ef85ab39..52ff4f021b 100644 --- a/src/android/gradle/wrapper/gradle-wrapper.properties +++ b/src/android/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sun Feb 21 18:16:59 EST 2021 +#Sun Sep 15 13:31:11 AWST 2024 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.10-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip