1diff --git a/android/src/main/java/expo/modules/sharing/SharingRecords.kt b/android/src/main/java/expo/modules/sharing/SharingRecords.kt
2index 0b87b53f632e82f9b4c09c066d5a67e4ab2525a4..65f1c57faef3ba8caac9e137341f2b8312bb5f86 100644
3--- a/android/src/main/java/expo/modules/sharing/SharingRecords.kt
4+++ b/android/src/main/java/expo/modules/sharing/SharingRecords.kt
5@@ -52,7 +52,8 @@ enum class ContentType(val value: String) : Enumerable {
6 internal data class SharePayload(
7 @Field var value: String = "",
8 @Field var shareType: ShareType = ShareType.Text,
9- @Field var mimeType: String = "text/plain"
10+ @Field var mimeType: String = "text/plain",
11+ @Field var originalName: String? = null
12 ) : Record
13
14 @OptimizedRecord
15diff --git a/android/src/main/java/expo/modules/sharing/dataParsers/SimpleShareIntentDataParser.kt b/android/src/main/java/expo/modules/sharing/dataParsers/SimpleShareIntentDataParser.kt
16index 3381c5fd207ebb4cd8e0301aac59d307939ff162..481cdb4bc64ea5ae49919071f686324f6d56d55c 100644
17--- a/android/src/main/java/expo/modules/sharing/dataParsers/SimpleShareIntentDataParser.kt
18+++ b/android/src/main/java/expo/modules/sharing/dataParsers/SimpleShareIntentDataParser.kt
19@@ -3,6 +3,7 @@ package expo.modules.sharing
20 import android.content.Context
21 import android.content.Intent
22 import android.net.Uri
23+import android.provider.OpenableColumns
24
25 internal class SimpleShareIntentDataParser {
26 companion object {
27@@ -17,25 +18,26 @@ internal class SimpleShareIntentDataParser {
28 }
29
30 private fun handleSendAction(context: Context, intent: Intent, type: String): List<SharePayload> {
31- return if (type == "text/plain") {
32- val text = intent.getStringExtra(Intent.EXTRA_TEXT) ?: return emptyList()
33- val isUrl = android.util.Patterns.WEB_URL.matcher(text).matches()
34-
35- listOf(
36+ val stream = intent.getParcelableExtraCompat<Uri>(Intent.EXTRA_STREAM)
37+ val text = intent.getStringExtra(Intent.EXTRA_TEXT)
38+ if (stream == null) {
39+ if (!type.startsWith("text/") || text == null) return emptyList()
40+ return listOf(
41 SharePayload().apply {
42 value = text
43- shareType = if (isUrl) {
44- ShareType.Url
45- } else {
46- ShareType.Text
47- }
48- mimeType = "text/plain"
49+ shareType = if (android.util.Patterns.WEB_URL.matcher(text).matches()) ShareType.Url else ShareType.Text
50+ mimeType = type
51 }
52 )
53- } else {
54- val uri = intent.getParcelableExtraCompat<Uri>(Intent.EXTRA_STREAM)
55- listOfNotNull(uri?.let { createUriPayload(context, it, type) })
56 }
57+ val filePayload = createUriPayload(context, stream, type)
58+ if (text.isNullOrBlank()) return listOf(filePayload)
59+ val textPayload = SharePayload().apply {
60+ value = text
61+ shareType = if (android.util.Patterns.WEB_URL.matcher(text).matches()) ShareType.Url else ShareType.Text
62+ mimeType = "text/plain"
63+ }
64+ return listOf(textPayload, filePayload)
65 }
66
67 private fun handleSendMultipleAction(context: Context, intent: Intent, type: String): List<SharePayload> {
68@@ -45,10 +47,25 @@ internal class SimpleShareIntentDataParser {
69
70 private fun createUriPayload(context: Context, uri: Uri, defaultType: String): SharePayload {
71 val specificType = context.contentResolver.getType(uri) ?: defaultType
72+ // A blank DISPLAY_NAME must stay null: consumers treat originalName as
73+ // the attachment name, and an empty name fails contract validation.
74+ val displayName = runCatching {
75+ context.contentResolver.query(
76+ uri,
77+ arrayOf(OpenableColumns.DISPLAY_NAME),
78+ null,
79+ null,
80+ null
81+ )?.use { cursor ->
82+ val column = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
83+ if (column >= 0 && cursor.moveToFirst()) cursor.getString(column) else null
84+ }
85+ }.getOrNull()?.takeIf { it.isNotBlank() }
86 return SharePayload().apply {
87 value = uri.toString()
88- shareType = ShareType.fromMimeType(specificType)
89+ shareType = if (specificType.startsWith("text/")) ShareType.File else ShareType.fromMimeType(specificType)
90 mimeType = specificType
91+ originalName = displayName
92 }
93 }
94 }
95diff --git a/build/Sharing.types.d.ts b/build/Sharing.types.d.ts
96index 74544e0728d5f845351693d8d90596abae42eaea..92bd2f53108ac717f1ef7292fe89aea05c676c5e 100644
97--- a/build/Sharing.types.d.ts
98+++ b/build/Sharing.types.d.ts
99@@ -100,6 +100,11 @@ export type SharePayload = {
100 * @default 'text/plain'
101 */
102 mimeType?: string;
103+ /**
104+ * The display name of a shared file, when the source app provided one.
105+ * Populated on Android from the content resolver's `DISPLAY_NAME`.
106+ */
107+ originalName?: string | null;
108 };
109 export type BaseResolvedSharePayload = SharePayload & {
110 /**
111diff --git a/src/Sharing.types.ts b/src/Sharing.types.ts
112index 18af320420e7c01a8ffbd7fa5347320409f905d8..3a52b70a20efbc588ad5ca974c38c951e5757c97 100644
113--- a/src/Sharing.types.ts
114+++ b/src/Sharing.types.ts
115@@ -108,6 +108,12 @@ export type SharePayload = {
116 * @default 'text/plain'
117 */
118 mimeType?: string;
119+
120+ /**
121+ * The display name of a shared file, when the source app provided one.
122+ * Populated on Android from the content resolver's `DISPLAY_NAME`.
123+ */
124+ originalName?: string | null;
125 };
126
127 export type BaseResolvedSharePayload = SharePayload & {