@@ -16,6 +16,7 @@ import android.view.KeyEvent
1616import android.view.View
1717import androidx.core.view.ViewCompat
1818import androidx.core.view.WindowInsetsCompat
19+ import androidx.core.content.IntentCompat
1920import android.webkit.MimeTypeMap
2021import com.facebook.react.ReactActivity
2122import com.facebook.react.ReactActivityDelegate
@@ -225,6 +226,36 @@ class MainActivity : ReactActivity() {
225226
226227 private var jsIsListening = false
227228 private var handledIntentHash: String? = null
229+ private fun extractSharedUris (intent : Intent ): List <Uri > {
230+ val action = intent.action
231+ if (Intent .ACTION_SEND != action && Intent .ACTION_SEND_MULTIPLE != action) {
232+ return emptyList()
233+ }
234+
235+ val uris = mutableListOf<Uri >()
236+
237+ intent.clipData?.let { clip ->
238+ for (i in 0 until clip.itemCount) {
239+ clip.getItemAt(i)?.uri?.let { uris.add(it) }
240+ }
241+ }
242+
243+ // Avoid getParcelableArrayListExtra() here: some senders incorrectly use ACTION_SEND_MULTIPLE
244+ // but provide a single Uri in EXTRA_STREAM, which would cause a ClassCast log/warning.
245+ when (val streamExtra = intent.extras?.get(Intent .EXTRA_STREAM )) {
246+ is Uri -> uris.add(streamExtra)
247+ is ArrayList <* > -> streamExtra.filterIsInstance<Uri >().forEach { uris.add(it) }
248+ else -> {
249+ }
250+ }
251+
252+ if (uris.isEmpty()) {
253+ IntentCompat .getParcelableExtra(intent, Intent .EXTRA_STREAM , Uri ::class .java)?.let { uris.add(it) }
254+ }
255+
256+ return uris.distinct()
257+ }
258+
228259 private fun handleIntent () {
229260 val intent = cachedIntent ? : return
230261 val rc = reactActivityDelegate?.getCurrentReactContext() ? : return
@@ -237,82 +268,87 @@ class MainActivity : ReactActivity() {
237268 // Here we are just reading from the notification bundle.
238269 // If other sources start the app, we can get their intent data the same way.
239270 val bundleFromNotification = intent.getBundleExtra(" notification" )
240- if (bundleFromNotification == null ) {
241- cachedIntent = null
242- return
243- }
244271
245- // Prevent duplicate handling of the same notification
246- val convID = bundleFromNotification.getString(" convID" ) ? : bundleFromNotification.getString(" c" )
247- val messageId = bundleFromNotification.getString(" msgID" ) ? : bundleFromNotification.getString(" d" ) ? : " "
248- val intentHash = " ${convID} _${messageId} "
249- if (handledIntentHash == intentHash) {
250- NativeLogger .info(" MainActivity.handleIntent skipping duplicate notification: $intentHash " )
251- cachedIntent = null
252- return
253- }
254- handledIntentHash = intentHash
255- NativeLogger .info(" MainActivity.handleIntent processing notification: $intentHash " )
256- cachedIntent = null
257- intent.removeExtra(" notification" )
258- val action = intent.action
259- var uris_: Array <Uri ?>? = null
260- if (Intent .ACTION_SEND_MULTIPLE == action) {
261- val alUri = intent.getParcelableArrayListExtra(Intent .EXTRA_STREAM , Uri ::class .java)
262- uris_ = alUri?.toTypedArray<Uri ?>()
263- } else if (Intent .ACTION_SEND == action) {
264- val oneUri = intent.getParcelableExtra(Intent .EXTRA_STREAM , Uri ::class .java)
265- uris_ = arrayOf(oneUri)
266- }
267- intent.removeExtra(Intent .EXTRA_STREAM )
268- val uris = uris_
269- val subject = intent.getStringExtra(Intent .EXTRA_SUBJECT )
270- intent.removeExtra(Intent .EXTRA_SUBJECT )
271- val text = intent.getStringExtra(Intent .EXTRA_TEXT )
272- intent.removeExtra(Intent .EXTRA_TEXT )
273- val sb = StringBuilder ()
274- if (subject != null ) {
275- sb.append(subject)
276- }
277- if (subject != null && text != null ) {
278- sb.append(" " )
279- }
280- if (text != null ) {
281- sb.append(text)
272+ var didSomething = false
273+
274+ if (bundleFromNotification != null ) {
275+ // Prevent duplicate handling of the same notification
276+ val convID = bundleFromNotification.getString(" convID" ) ? : bundleFromNotification.getString(" c" )
277+ val messageId = bundleFromNotification.getString(" msgID" ) ? : bundleFromNotification.getString(" d" ) ? : " "
278+ val intentHash = " ${convID} _${messageId} "
279+ val shouldEmitNotification = handledIntentHash != intentHash
280+ if (! shouldEmitNotification) {
281+ NativeLogger .info(" MainActivity.handleIntent skipping duplicate notification: $intentHash " )
282+ } else {
283+ handledIntentHash = intentHash
284+ NativeLogger .info(" MainActivity.handleIntent processing notification: $intentHash " )
285+
286+ // If there are any other bundle sources we care about, emit them here
287+ val bundle1 = bundleFromNotification.clone() as Bundle
288+ val bundle2 = bundleFromNotification.clone() as Bundle
289+ val payload1 = Arguments .fromBundle(bundle1)
290+ emitter.emit(
291+ " initialIntentFromNotification" ,
292+ payload1
293+ )
294+ val payload2 = Arguments .fromBundle(bundle2)
295+ emitter.emit(
296+ " onPushNotification" ,
297+ payload2
298+ )
299+ didSomething = true
300+ }
301+
302+ intent.removeExtra(" notification" )
282303 }
283304
284- val textPayload = sb.toString()
305+ val action = intent.action
306+ if (Intent .ACTION_SEND == action || Intent .ACTION_SEND_MULTIPLE == action) {
307+ val uris = extractSharedUris(intent)
308+ val subject = intent.getStringExtra(Intent .EXTRA_SUBJECT )
309+ val text = intent.getStringExtra(Intent .EXTRA_TEXT )
310+
311+ intent.removeExtra(Intent .EXTRA_STREAM )
312+ intent.removeExtra(Intent .EXTRA_SUBJECT )
313+ intent.removeExtra(Intent .EXTRA_TEXT )
314+ intent.setClipData(null )
315+
316+ val sb = StringBuilder ()
317+ if (subject != null ) {
318+ sb.append(subject)
319+ }
320+ if (subject != null && text != null ) {
321+ sb.append(" " )
322+ }
323+ if (text != null ) {
324+ sb.append(text)
325+ }
285326
286- val filePaths = uris?.mapNotNull { uri ->
287- readFileFromUri(rc, uri)
288- }?.toTypedArray() ? : emptyArray()
327+ val textPayload = sb.toString()
328+ val filePaths = uris.mapNotNull { uri ->
329+ readFileFromUri(rc, uri)
330+ }.toTypedArray()
289331
290- // If there are any other bundle sources we care about, emit them here
291- // bundleFromNotification is already checked for null above, so it's safe here
292- val bundle1 = bundleFromNotification.clone() as Bundle
293- val bundle2 = bundleFromNotification.clone() as Bundle
294- var payload1 = Arguments .fromBundle(bundle1)
295- emitter.emit(
296- " initialIntentFromNotification" ,
297- payload1
298- )
299- var payload2 = Arguments .fromBundle(bundle2)
300- emitter.emit(
301- " onPushNotification" ,
302- payload2
303- )
304- if (filePaths.size != 0 ) {
305- val args = Arguments .createMap()
306- val lPaths = Arguments .createArray()
307- for (path in filePaths) {
308- lPaths.pushString(path)
332+ if (filePaths.isNotEmpty()) {
333+ val args = Arguments .createMap()
334+ val lPaths = Arguments .createArray()
335+ for (path in filePaths) {
336+ lPaths.pushString(path)
337+ }
338+ args.putArray(" localPaths" , lPaths)
339+ emitter.emit(" onShareData" , args)
340+ didSomething = true
341+ } else if (textPayload.isNotEmpty()) {
342+ val args = Arguments .createMap()
343+ args.putString(" text" , textPayload)
344+ emitter.emit(" onShareData" , args)
345+ didSomething = true
309346 }
310- args.putArray(" localPaths" , lPaths)
311- emitter.emit(" onShareData" , args)
312- } else if (textPayload.length > 0 ) {
313- val args = Arguments .createMap()
314- args.putString(" text" , textPayload)
315- emitter.emit(" onShareData" , args)
347+ }
348+
349+ cachedIntent = null
350+ if (! didSomething) {
351+ return
316352 }
317353 }
318354
0 commit comments