Skip to content

Bug: Save to Gallery does nothing on Android 16 #473

Description

@carmilso

Summary

On Android 16, Save to Gallery appears to complete, but no file is written to the gallery and no new item appears in MediaStore.

Affected package in my case: org.forkgram.messenger

Environment

  • App: Forkgram (org.forkgram.messenger)
  • Version observed: 12.8.2.0
  • Device: OnePlus 8T
  • Android: 16 (SDK 36)
  • targetSdkVersion: 35

Reproduction

  1. Open any image in PhotoViewer.
  2. Tap Save to Gallery.
  3. Wait for completion.
  4. Check Pictures/, Movies/, Download/Telegram/, and gallery apps.

Actual result

  • No file is saved.
  • No new MediaStore row appears.
  • No file appears in:
    • Pictures/Telegram/
    • Movies/Telegram/
    • Download/Telegram/
    • Android/media/org.forkgram.messenger/Telegram/...

Expected result

The selected image/video should be saved and immediately visible in the system gallery.

Investigation

There seem to be two separate Android 16 related problems:

  1. Intermittent failure creating app external dirs:
Failed to ensure /storage/emulated/0/Android/data/org.forkgram.messenger/files
java.lang.IllegalStateException: Failed to prepare /storage/emulated/0/Android/data/org.forkgram.messenger/files
at android.os.storage.IStorageManager$Stub$Proxy.mkdirs
at android.app.ContextImpl.getExternalFilesDir
at org.telegram.messenger.AndroidUtilities.getLogsDir

This showed up during debugging and may indicate stricter external storage behavior on Android 16.

  1. Main issue for manual Save to Gallery:

PhotoViewer calls:

MediaController.saveFile(...)

On Android 29+, this goes through:

private static Uri saveFileInternal(int type, File sourceFile, String filename)

Current implementation inserts directly into MediaStore, writes bytes, and returns the URI, but it does not use a robust pending/finalize flow and depends on MIME/extension inference that can become invalid or empty for some inputs.

In my tests on Android 16:

  • Save to Gallery produced no output file.
  • Forcing app ops like WRITE_MEDIA_IMAGES did not fix it.
  • Manually creating /sdcard/Android/data/org.forkgram.messenger/files did not fix it either.

So this does not look like a simple permission toggle issue anymore. It looks like the MediaStore write path needs to be more defensive on newer Android versions.

Proposed fix

Harden MediaController.saveFileInternal(...) and related Android 29+ save paths:

  • Set MediaStore.MediaColumns.IS_PENDING = 1 before writing.
  • Write using openOutputStream(uri, "w").
  • Set IS_PENDING = 0 after a successful copy.
  • Delete the inserted row if writing fails or returns a null stream.
  • Normalize empty/invalid MIME and extension values before insertion.

I tested a local patch with the above changes in:

TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java

Specifically:

  • added finishPendingMediaUri(...)
  • added deleteMediaUri(...)
  • normalized extension/MIME handling
  • applied the same IS_PENDING flow to motion photo save paths too

Candidate areas

  • TMessagesProj/src/main/java/org/telegram/messenger/MediaController.java
  • TMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.java

Relevant call sites:

  • PhotoViewer manual save flow
  • PeerStoriesView.saveToGallery()
  • auto-save flows using AndroidUtilities.addMediaToGallery(...)

Notes

AndroidUtilities.addMediaToGallery(...) still relies on:

Intent.ACTION_MEDIA_SCANNER_SCAN_FILE

That may still be acceptable for legacy/public-file paths, but manual Save to Gallery on Android 29+ should be handled through MediaStore correctly end-to-end.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions