summaryrefslogtreecommitdiff
path: root/android-app/app/src
diff options
context:
space:
mode:
Diffstat (limited to 'android-app/app/src')
-rw-r--r--android-app/app/src/main/AndroidManifest.xml18
-rw-r--r--android-app/app/src/main/kotlin/org/terst/nav/MainActivity.kt20
2 files changed, 26 insertions, 12 deletions
diff --git a/android-app/app/src/main/AndroidManifest.xml b/android-app/app/src/main/AndroidManifest.xml
index 35f8dd3..196932d 100644
--- a/android-app/app/src/main/AndroidManifest.xml
+++ b/android-app/app/src/main/AndroidManifest.xml
@@ -34,26 +34,30 @@
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
- <!-- application/gpx+xml: standard MIME type, recognised on Android 12+ -->
+ <!-- GPX as standard MIME type (used by apps that know the type) -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.BROWSABLE" />
<data android:mimeType="application/gpx+xml" />
</intent-filter>
- <!-- application/gpx: older variant sent by some file managers and email clients -->
+ <!-- GPX older variant -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
- <category android:name="android.intent.category.BROWSABLE" />
<data android:mimeType="application/gpx" />
</intent-filter>
- <!-- file:// URIs from legacy file managers; extension filtered in code -->
+ <!-- GPX as XML — Android's MimeTypeMap often maps .gpx to text/xml because
+ application/gpx+xml isn't in the base system database. Code checks the
+ display name before parsing. -->
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
- <data android:scheme="file" android:host="*" android:pathSuffix=".gpx"
- android:mimeType="*/*" />
+ <data android:mimeType="text/xml" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.VIEW" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <data android:mimeType="application/xml" />
</intent-filter>
</activity>
</application>
diff --git a/android-app/app/src/main/kotlin/org/terst/nav/MainActivity.kt b/android-app/app/src/main/kotlin/org/terst/nav/MainActivity.kt
index 82c238e..07adb35 100644
--- a/android-app/app/src/main/kotlin/org/terst/nav/MainActivity.kt
+++ b/android-app/app/src/main/kotlin/org/terst/nav/MainActivity.kt
@@ -3,6 +3,7 @@ package org.terst.nav
import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
+import android.provider.OpenableColumns
import android.util.Log
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@@ -141,12 +142,21 @@ class MainActivity : AppCompatActivity(), SafetyFragment.SafetyListener {
private fun handleIncomingGpx(intent: Intent?) {
if (intent?.action != Intent.ACTION_VIEW) return
val uri = intent.data ?: return
- // Accept if the MIME type is gpx-related OR if the URI's last path segment
- // ends in .gpx — some Android versions / file managers send application/octet-stream
- // for file types they don't recognise.
val mime = intent.type ?: contentResolver.getType(uri) ?: ""
- val byExtension = uri.lastPathSegment?.lowercase()?.endsWith(".gpx") == true
- if (!mime.contains("gpx", ignoreCase = true) && !byExtension) return
+ when {
+ // Known GPX MIME types — proceed immediately.
+ mime.contains("gpx", ignoreCase = true) -> Unit
+ // Generic XML MIME (text/xml, application/xml): the Android system MimeTypeMap
+ // often lacks application/gpx+xml for .gpx, so file managers fall back to an
+ // XML type. Verify the display name before parsing to avoid opening random XML.
+ mime.contains("xml", ignoreCase = true) -> {
+ val displayName = contentResolver.query(
+ uri, arrayOf(OpenableColumns.DISPLAY_NAME), null, null, null
+ )?.use { c -> if (c.moveToFirst()) c.getString(0) else null }
+ if (displayName?.lowercase()?.endsWith(".gpx") != true) return
+ }
+ else -> return
+ }
lifecycleScope.launch {
runCatching {
val points = withContext(Dispatchers.IO) {