@@ -391,9 +391,13 @@ private void dismissProgressDialog() {
391391 }
392392 }
393393
394+ private static final int REQUEST_SHARE = 1001 ;
395+
394396 /**
395397 * Creates and launches a share intent for the processed (clean) media file.
396- * The temporary file will be deleted after sharing completes (when activity resumes).
398+ * Uses startActivityForResult so we only clean up after the chooser returns,
399+ * not when it merely pauses this activity (which would delete the file before
400+ * the receiving app has read it).
397401 *
398402 * @param isVideo Whether the processed file is a video (true) or image (false)
399403 * @param cleanedFileUri The URI of the processed file to share
@@ -403,60 +407,57 @@ private void shareCleanFile(boolean isVideo, Uri cleanedFileUri) {
403407 SentryManager .setCustomKey ("cleaned_uri" , cleanedFileUri != null ? cleanedFileUri .toString () : "null" );
404408
405409 if (cleanedFileUri != null ) {
406- // Create a share intent with the appropriate MIME type
410+ String mimeType = isVideo ? "video/*" : "image/*" ;
411+
407412 Intent shareIntent = new Intent (Intent .ACTION_SEND );
408- shareIntent .setType (isVideo ? "video/*" : "image/*" );
413+ shareIntent .setType (mimeType );
409414 shareIntent .putExtra (Intent .EXTRA_STREAM , cleanedFileUri );
410415 shareIntent .addFlags (Intent .FLAG_GRANT_READ_URI_PERMISSION );
411416
412- // Mark that sharing has been initiated
413- sharingInitiated = true ;
417+ // Proactively grant read permission to every app that can handle this intent.
418+ // This is required because some apps receive the URI through the chooser's
419+ // indirection layer, which doesn't automatically forward FLAG_GRANT_READ_URI_PERMISSION.
420+ for (android .content .pm .ResolveInfo resolveInfo :
421+ getPackageManager ().queryIntentActivities (shareIntent , 0 )) {
422+ String packageName = resolveInfo .activityInfo .packageName ;
423+ grantUriPermission (packageName , cleanedFileUri ,
424+ Intent .FLAG_GRANT_READ_URI_PERMISSION );
425+ }
414426
415- // Launch the share intent
416- // Note: We don't finish() immediately so we can cleanup in onResume()
427+ Intent chooser = Intent .createChooser (shareIntent , getString (R .string .share_chooser_title ));
428+ // The chooser itself is a separate process; it also needs the flag so it
429+ // can forward the URI to whichever app the user picks.
430+ chooser .addFlags (Intent .FLAG_GRANT_READ_URI_PERMISSION );
431+
432+ sharingInitiated = true ;
417433 SentryManager .log ("Launching share intent" );
418- startActivity ( Intent . createChooser ( shareIntent , getString ( R . string . share_chooser_title )) );
434+ startActivityForResult ( chooser , REQUEST_SHARE );
419435 } else {
420- // Handle case where processing didn't produce a valid file
421436 SentryManager .log ("Cleaned file URI is null" );
422437 finishWithError ("Failed to get cleaned file" );
423438 }
424439 } catch (Exception e ) {
425- // Log and handle any errors during sharing
426440 SentryManager .recordException (e );
427441 finishWithError ("Error sharing clean file: " + e .getMessage ());
428442 }
429443 }
430444
431445 /**
432- * Called when the activity is paused (e.g., when share chooser is shown).
433- * This is where we can detect that sharing has started.
446+ * Called when the share chooser returns. This is the correct place to clean up
447+ * the temporary file — it fires only after the chooser is fully dismissed, so the
448+ * receiving app has already obtained its copy of the file via the FileProvider URI.
434449 */
435450 @ Override
436- protected void onPause () {
437- super .onPause ();
438- // When activity pauses, it means the share chooser or target app is shown
439- // We'll cleanup when the activity resumes (user returns from sharing)
440- }
441-
442- /**
443- * Called when the activity resumes (e.g., when user returns from share chooser).
444- * This is where we cleanup the temporary file after sharing is complete.
445- */
446- @ Override
447- protected void onResume () {
448- super .onResume ();
449-
450- // If sharing was initiated and we're resuming, it means the user has
451- // interacted with the share chooser (either shared or cancelled)
452- // Clean up the temporary file now
453- if (sharingInitiated ) {
451+ protected void onActivityResult (int requestCode , int resultCode , Intent data ) {
452+ super .onActivityResult (requestCode , resultCode , data );
453+ if (requestCode == REQUEST_SHARE ) {
454+ SentryManager .log ("Share chooser returned, cleaning up" );
454455 cleanupProcessedFile ();
455- // Finish the activity since sharing is complete
456456 finish ();
457457 }
458458 }
459-
459+
460+
460461 /**
461462 * Deletes the temporary processed file from disk.
462463 * This is called after sharing completes to avoid saving files to disk.
0 commit comments