| 1 | diff --git a/android/src/main/java/expo/modules/sharing/SharingRecords.kt b/android/src/main/java/expo/modules/sharing/SharingRecords.kt |
| 2 | index 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 |
| 15 | diff --git a/android/src/main/java/expo/modules/sharing/dataParsers/SimpleShareIntentDataParser.kt b/android/src/main/java/expo/modules/sharing/dataParsers/SimpleShareIntentDataParser.kt |
| 16 | index 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 | } |
| 95 | diff --git a/build/Sharing.types.d.ts b/build/Sharing.types.d.ts |
| 96 | index 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 | /** |
| 111 | diff --git a/src/Sharing.types.ts b/src/Sharing.types.ts |
| 112 | index 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 & { |