On my current project, we need to “pre-load” many tablets with a set of videos. We want to script the loading of the videos, so we started with adb. The videos should appear in Android’s gallery app so they can be viewed like any other video. Finally, we have some folder structure for the videos that should also appear in the gallery.
Getting this working was a couple hours’ challenge. Copying the files on to the tablet was easy. We did that in bulk using adb’s push command: adb push Movies/ /mnt/sdcard/Movies/remote_video.mp4
This is not enough to make the video appear in the gallery. Rather than scanning or watching the filesystem, Android’s gallery reads a ContentProvider that lists the media on the device. The ContentProvider is populated by a MediaScannerService that looks for media at particular times and saves information about any discovered music, videos or images.
We needed a way to trigger the MediaScanner. Naively, we tried restarting the tablet, but that didn’t get the videos in to the gallery. Next, we asked google. We found several general descriptions of the process, but not in enough detail to easily duplicate it. Here is what we discovered after experimentation.
The basic form of the command is:
adb shell "am broadcast -a -d "
or you can run it within an dab shell on a device:
adb shell
am broadcast -a -d
What should the <ACTION> and <DATA_URI> values be?
Action needs to be a recognized constant value from the Android documentation. I kept tripping myself up by using the constant name, rather than the value. Values are in the documentation for the constants:
The two that we found useful were android.intent.action.MEDIA_MOUNTED and android.intent.action.MEDIA_SCANNER_SCAN_FILE. As described in their respective documentation, MEDIA_MOUNTED takes a path to scan as its data_uri and MEDIA_SCANNER_SCAN_FILE takes a path to a single file. For our use case, we ran the command:
adb -d shell "am broadcast -a android.intent.action.MEDIA_MOUNTED -d file:///mnt/sdcard/Movies/"
We had originally tried to use /mnt/sdcard/ as the full path, because it didn’t seem that there would be any harm in scanning the whole card. However, because different system apps watch paths on the sdcard, trying to say the whole card was mounted causes a permissions error.
Because of that error, we had to be specify /Movies/, which did not trigger the error. If we do need to load music or images, we will be able to pass those specific paths with the same intent.
(Note: I’ve been unable to reproduce the permissions error more recently, so there is another factor involved. One difference could be that the tablets reporting the error were running 4.0.3, but we have since moved to tablets running 4.1.1.)