Skip to content

Add --media-scan to register pushed files with MediaStore#6852

Open
eret9616 wants to merge 4 commits into
Genymobile:devfrom
eret9616:feat/media-scan-on-push
Open

Add --media-scan to register pushed files with MediaStore#6852
eret9616 wants to merge 4 commits into
Genymobile:devfrom
eret9616:feat/media-scan-on-push

Conversation

@eret9616
Copy link
Copy Markdown

Refs #6851 (also discussed in #6200).

Pushed files (especially images dragged into the window) don't show in the gallery: MediaStore isn't notified and most vendor galleries filter /sdcard/Download/ out. See the linked issue for the full reasoning.

This adds an opt-in --media-scan:

  • routes image/video extensions to /sdcard/Pictures/ and /sdcard/Movies/ when --push-target is not set
  • runs cmd media_scanner scan-file after each push (Android 8+), with am broadcast MEDIA_SCANNER_SCAN_FILE as fallback for ROMs that strip the shell service (OnePlus / ColorOS confirmed — first call returns Can't find service)
  • explicit --push-target keeps full control
  • default off, no behavior change for existing users

Tested on OnePlus PGZ110 (Android 13), drag-and-drop a .png shows up in the gallery within seconds.

When a file is dropped on the scrcpy window, it is pushed to the device
with "adb push" but MediaStore is not updated, so gallery apps cannot
see the new file. Many gallery apps also filter out /sdcard/Download/,
which is the default push target.

With --media-scan enabled:
 - if --push-target is not set, image files (.jpg, .png, .heic, ...)
   are pushed to /sdcard/Pictures/ and video files (.mp4, .mkv, ...)
   to /sdcard/Movies/ instead of /sdcard/Download/;
 - after each successful push, "cmd media_scanner scan-file <path>"
   is invoked on the device to trigger a MediaStore scan.

An explicit --push-target still wins for all file types and is scanned
from that location.

The cmd media_scanner shell command is available since Android 8.0.
@rom1v
Copy link
Copy Markdown
Collaborator

rom1v commented May 19, 2026

On a Pixel 8 with Android 16:

$ adb shell cmd media_scanner 
cmd: Can't find service: media_scanner

snprintf is used in build_remote_path() but the header was missing,
which fails on toolchains that don't pull it in transitively (e.g.
gcc on Linux with -std=c11).
@eret9616
Copy link
Copy Markdown
Author

eret9616 commented May 20, 2026

Huh, didn't realize stock Android dropped it too — thought it was just OEM ROMs. I'll fix the description and the comment in the code.

The PR already falls back to am broadcast MEDIA_SCANNER_SCAN_FILE if the first call fails — that's how it works on my OnePlus. But broadcast got deprecated in Android 12, so I don't know if it still works on Pixel 8 / Android 16, and I don't have either device.

@rom1v

Could you try this on the Pixel 8 and see if the gallery picks it up?

adb shell am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE -d file:///sdcard/Pictures/foo.jpg

If that's also dead, only path I see is going through MediaStore from the server side (content insert or similar). Wanted to confirm the fallback status first.

@yume-chan
Copy link
Copy Markdown
Contributor

https://developer.android.com/reference/android/media/MediaScannerConnection#scanFile(android.content.Context,%20java.lang.String[],%20java.lang.String[],%20android.media.MediaScannerConnection.OnScanCompletedListener)

public static void scanFile (Context context, 
                String[] paths, 
                String[] mimeTypes, 
                MediaScannerConnection.OnScanCompletedListener callback)

The API itself was added in Android 2.2, I only tested it on Andorid 13 and Android 16. context can be fake context, mimeTypes and callback can be null (in fact mimeTypes is straightly ignored in recent Android versions)

Also mentioned by Context#getExternalFilesDir: https://developer.android.com/reference/android/content/Context#:~:text=Though%20these%20files%20are%20not%20automatically%20scanned%20by%20the%20media%20scanner%2C%20you%20can%20explicitly%20add%20them%20to%20the%20media%20database%20with%20MediaScannerConnection.scanFile.

The previous implementation used `adb shell cmd media_scanner scan-file`
with `am broadcast MEDIA_SCANNER_SCAN_FILE` as fallback. Both are
unreliable on modern Android:
 - `cmd media_scanner` is missing on stock Android 16 (Pixel) and many
   OEM ROMs;
 - `MEDIA_SCANNER_SCAN_FILE` broadcast was deprecated in Android 12.

Instead, send a new SCAN_FILE control message after a successful push,
and let the scrcpy server invoke MediaStore's `scan_file` provider call
directly through `ContentResolver.call(MediaStore.AUTHORITY, "scan_file",
path, null)`, reusing the existing FakeContext. This is the same path
that `MediaStore.scanFile()` and `adb shell content call --uri
content://media --method scan_file --arg <path>` go through, and works
on every Android version exposing MediaStore.

Verified on OnePlus PGZ110 (Android 13): files dragged into the scrcpy
window appear in the gallery within seconds, with owner_package_name=
com.android.shell as expected.
@eret9616
Copy link
Copy Markdown
Author

eret9616 commented May 21, 2026

@yume-chan thanks, went with your suggestion. Server now handles a new SCAN_FILE control message and calls ContentResolver.call(MediaStore.AUTHORITY, "scan_file", ...) through the FakeContext. (MediaStore.scanFile() itself is hide on SDK 36, so calling the provider method directly — same path internally.)

Works on my OnePlus 13. @rom1v mind giving it another go on the Pixel when you get a chance?

@rom1v
Copy link
Copy Markdown
Collaborator

rom1v commented May 22, 2026

This works on a Pixel 8:

adb push file.jpg /sdcard/Download
adb shell am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE -d file:///sdcard/Download

I also found an old commit 190a90f (on branch scan_media). I don't remember why I abandoned it, probably because it did not work reliably across devices.

But if it works now using MediaStore.scanFile(), great 👍

However, I would prefer not to auto-detect images/videos to change the target directory, just push to "push-target" whatever it is, then scan this directory.

Also, if there are no downsides, I think an option --media-scan is not necessary, just do it unconditionally.

Per review feedback from rom1v on Genymobile#6852:

 - drop the --media-scan opt-in flag: MediaStore scan is now always
   triggered after a successful drag-and-drop push;
 - drop the image/video extension routing to /sdcard/Pictures/ and
   /sdcard/Movies/: tests on Pixel 8 / Android 17 and OnePlus PGZ110
   / ColorOS 13 confirm Google Photos main view only surfaces DCIM
   folders regardless of target dir, while scan alone is enough to
   make files reachable via the system Photo Picker and gallery
   folder views.

The CLI surface goes back to a single --push-target option; the
SCAN_FILE control message path introduced previously is preserved.
@eret9616
Copy link
Copy Markdown
Author

Done in fda146c — both the routing and the --media-scan flag are gone, scan runs unconditionally now.

Tested on a Pixel 8 emulator (Android 17) and the OnePlus PGZ110 from the original report, both fine.

Doc updated accordingly.

@rom1v
Copy link
Copy Markdown
Collaborator

rom1v commented May 25, 2026

Thank you. 👍

I made some changes, the resulting branch is scan-media.3.

Firstly, I removed the build_remote_path() to guess the target file, since the actual file path depends on the directories on the device.

For example:

adb push a /sdcard/Download/a

sometimes creates a file /sdcard/Download/a, but if /sdcard/Download/a was already an existing directory, it creates /sdcard/Download/a/a.

Instead, for simplicity, I always request to scan the "push target" directory (by default /sdcard/Download).

I also added unit tests for the control message serialization.


One remaining problem on:

Bundle out = FakeContext.get().getContentResolver().call(MediaStore.AUTHORITY, "scan_file", path, null);

Call requires API level 29 (current min is 21): android.content.ContentResolver#call

so it does not work on older versions (tested on Android 6).

We should probably use (the equivalent of):

adb shell am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE -d file:///sdcard/Download

(like in 190a90f)

as a fallback, or even as the main method (since it still works on Android 16).

@anotheruserofgithub
Copy link
Copy Markdown

On scan-media.3:

  • control_msg.c L350: scan media -> scan file
  • file_pusher.h L27: SCAN_MEDIA -> SCAN_FILE

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants