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
- Open any image in
PhotoViewer.
- Tap
Save to Gallery.
- Wait for completion.
- 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:
- 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.
- 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.
Summary
On Android 16,
Save to Galleryappears to complete, but no file is written to the gallery and no new item appears inMediaStore.Affected package in my case:
org.forkgram.messengerEnvironment
org.forkgram.messenger)12.8.2.0Reproduction
PhotoViewer.Save to Gallery.Pictures/,Movies/,Download/Telegram/, and gallery apps.Actual result
MediaStorerow appears.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:
This showed up during debugging and may indicate stricter external storage behavior on Android 16.
Save to Gallery:PhotoViewercalls:On Android 29+, this goes through:
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 Galleryproduced no output file.WRITE_MEDIA_IMAGESdid not fix it./sdcard/Android/data/org.forkgram.messenger/filesdid not fix it either.So this does not look like a simple permission toggle issue anymore. It looks like the
MediaStorewrite path needs to be more defensive on newer Android versions.Proposed fix
Harden
MediaController.saveFileInternal(...)and related Android 29+ save paths:MediaStore.MediaColumns.IS_PENDING = 1before writing.openOutputStream(uri, "w").IS_PENDING = 0after a successful copy.I tested a local patch with the above changes in:
Specifically:
finishPendingMediaUri(...)deleteMediaUri(...)IS_PENDINGflow to motion photo save paths tooCandidate areas
TMessagesProj/src/main/java/org/telegram/messenger/MediaController.javaTMessagesProj/src/main/java/org/telegram/messenger/AndroidUtilities.javaRelevant call sites:
PhotoViewermanual save flowPeerStoriesView.saveToGallery()AndroidUtilities.addMediaToGallery(...)Notes
AndroidUtilities.addMediaToGallery(...)still relies on:That may still be acceptable for legacy/public-file paths, but manual
Save to Galleryon Android 29+ should be handled throughMediaStorecorrectly end-to-end.