My app downloads .mp3 files to download folder. It works fine, but then no music player app is able to play it ("cannot play this type of files").
I have to reboot every time to force the system to run media scanner, to make it work.
I tried MediaScannerConnection, but it does not work on my API level (24)
File sdCard = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
MediaScannerConnection.scanFile(this, new String[]{sdCard.getPath()},
null, new MediaScannerConnection.OnScanCompletedListener() {
public void onScanCompleted(String path, Uri uri) {
// now visible in gallery
Toast.makeText(getBaseContext(), "files have been scanned dawg", Toast.LENGTH_LONG).show();
}
});
It does not show any toast.
I have found another method, but I have heard that it breaks from android 4.4
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory())));
This method breaks from android 7 apparently
File file = new File(absolutePath);
Uri uri = Uri.fromFile(file);
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri);
sendBroadcast(intent);
How do I make it work on api level 15-current? Is there any universal way? None of them worked on my device yet.
I am developing an Android app for Jellybean, KitKat and Lollipop and several different devices.
At the beginning of project, I used the Jellybean API library with target API 'anroid-18' using 'Samsung galaxy note 2014 edition'.
A few months later, the OS of the device started upgrading to KitKat OS, so I changed the library to 'android-19' in which version number is 4.4.2.
I have new device named Galaxy S tab 2 now.
I have the three versions and two devices now and my default API is 4.4.2.
The problem occurred when capturing pictures using the app:
if (Build.VERSION.SDK_INT >= AlopexBuild.VERSION_SUPPORT.KITKAT) {
Intent mediaScanIntent
= new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri contentUri = Uri.parse("file://"+ path);
mediaScanIntent.setData(contentUri);
sendBroadcast(mediaScanIntent);
} else {
sendBroadcast(
new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"+ path)));
}
The following code has no problem in Jellybean:
Intent mediaScanIntent
= new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri contentUri = Uri.parse("file://"+ path);
mediaScanIntent.setData(contentUri);
sendBroadcast(mediaScanIntent);
Why is this happening?
Jellybean OS + Kitkat API = Failed
Kitkat OS + Kitkat API = OK
Lollipop OS + KitKat API = OK
Problematic code is
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"+ path)));
According to the wiki articles references for each OS when releasing the new KitKat and Lolipop OS and moving from Jellybean they changed to a new kind of runtime enviroment. The code only compatible in this new enviroment, you'll need to try a different method for other enviroments like Jellybean.
See here and here
I am very new to Android development!
I am working on a camera-related app, and I encountered a problem that the pictures taken are not immediately displayed in 'Photos' app in Android 5.0.1, but when I restart the phone, and take a picture one more time, the previous pictures would all be displayed in 'Photos' app. And this problem only occurs in Android 5.0.1. I tried it on Android 4.3, and there isn't the problem.
And I do add the following codes in my program:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Intent mediaScanIntent = new Intent(
Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri contentUri = Uri.fromFile(new File("file://" + Environment.getExternalStorageDirectory() + "/DCIM")); //out is your output file
mediaScanIntent.setData(contentUri);
sendBroadcast(mediaScanIntent);
}
Could anybody help me out there please????
I have an application that makes changes to some of the files in the media folders (DCIM/Camera specifically)
After I make theses changes the application sends this broadcast in order to force the MediaScanner to run so that my changes get reflected in the Gallery app the next time it is opened.
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory())));
This works perfect on devices running stock android. However on devices with motoblur it fails and gives me this output in the log:
Permission Denial: broadcasting Intent { act=android.intent.action.MEDIA_MOUNTED dat=file:///mnt/sdcard } from com.my.package (pid=20882, uid=10109) requires com.motorola.blur.service.blur.Permissions.INTERACT_BLUR_SERVICE due to registered receiver BroadcastFilter{40a444c8 ReceiverList{40a22888 13696 com.motorola.blur.service.blur/10023 remote:40a340b8}}
Is there some way I can use this INTERACT_BLUR_SERVICE permission? Or is there some other way I can get the Media Scanner to run on command?
Souldn't adding this permission in your AndroidManifest solve the problem?... like this :
<uses-permission android:name=
"com.motorola.blur.service.blur.Permissions.INTERACT_BLUR_SERVICE"/>
I never found a way to trigger the media scanner. But I was pointed towards a different means of deleting the images and videos, rather than just deleting the files on the SD card, I now use a ContentResolver to delete the media.
Here is a snippet of how I've done it:
//Uri imgUri = Uri.parse("content://android.provider.MediaStore.Images.Media");
ContentResolver cr = getContentResolver();
int count = cr.delete(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null);
count += cr.delete(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, null, null);
Log.i(myTag, "Deleted " + count + " files from media database");
My app allows a user to save an image to their SD card. But I'm not sure how to make it appear in the gallery until you unmount and remount the SD card. I have googled for a couple of days with this problem but am not sure how to make it appear automatically. I found
this link but I'm not sure how to use the class. This is what i use to save the file. At the bottom of the try catch block is where I want to scan the sd card for new media.
FileOutputStream outStream = null;
File file = new File(dirPath, fileName);
try {
outStream = new FileOutputStream(file);
bm.compress(Bitmap.CompressFormat.JPEG, 100, outStream);
outStream.flush();
outStream.close();
} catch {
...
}
If anyone could point me in the right direction, I would appreciate.
I've tried plenty of different methods to trigger the MediaScanner, and these are my results.
SendBroadcast
The most simple and naive solution. It consists in executing the following instruction from your code:
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED,
Uri.parse("file://"+ Environment.getExternalStorageDirectory())));
However, this no longer works in KitKat devices, due to a lack of required permissions.
MediaScannerWrapper
As posted here (per #Brian's answer), it consists in wrapping a MediaScannerConnection instance in order to trigger the scan() method over a specific directory. This method has proven to be working fine for 4.3 and below, but still no luck with KitKat (4.4+).
FileWalker
One of the many Play Store apps that tries to overcome the MediaStore's lack of commitment to update its database is ReScan SD. It sends a lot of different broadcasts:
sendBroadcast(new Intent("android.intent.action.MEDIA_MOUNTED", Uri.parse("file://" + Environment.getExternalStorageDirectory())));
sendBroadcast(new Intent("android.intent.action.MEDIA_MOUNTED", Uri.parse("file:///Removable")));
sendBroadcast(new Intent("android.intent.action.MEDIA_MOUNTED", Uri.parse("file:///Removable/SD")));
sendBroadcast(new Intent("android.intent.action.MEDIA_MOUNTED", Uri.parse("file:///Removable/MicroSD")));
sendBroadcast(new Intent("android.intent.action.MEDIA_MOUNTED", Uri.parse("file:///mnt/Removable/MicroSD")));
sendBroadcast(new Intent("android.intent.action.MEDIA_MOUNTED", Uri.parse("file:///mnt")));
sendBroadcast(new Intent("android.intent.action.MEDIA_MOUNTED", Uri.parse("file:///storage")));
sendBroadcast(new Intent("android.intent.action.MEDIA_MOUNTED", Uri.parse("file:///Removable")));
and tries to support KitKat by manually triggering the scan() method over each file of the base directory. Unfortunately, this is both very CPU-intensive and time-consuming, so it is not very recommended.
"The shell way"
The only thing that seem to work with KitKat in some cases is sending the broadcast via adb shell. So, this snippet allows you to do just that programmatically:
Runtime.getRuntime().exec("am broadcast -a android.intent.action.MEDIA_MOUNTED -d file://" + Environment.getExternalStorageDirectory());
It is more of an hack-ish way of doing it, but at the moment is the best I could come up with.
Bottom line
Each of the above solutions actually works for everything that is not KitKat. That's because, thanks to Justin, a bug has been found and issued to the official Tracker. This means that, until the bug is ironed out, we are left with no true KitKat support.
Which one to use? Among those, I would use the MediaScannerWrapper solution, together with the shell-ish approach (the last one).
Since the last answer I posted apparently wasn't an appropriate method, I found another method here. You basically create a wrapper class, initialize it, and then call the scan() method. Very helpful post. Let me know if this isn't appropriate either.
Use MediaScannerConnection:
http://developer.android.com/reference/android/media/MediaScannerConnection.html
It can be a little bit of a pain because of the multiple levels of asynchronous calls, so as of API 8 (Froyo) there is a helper function:
http://developer.android.com/reference/android/media/MediaScannerConnection.html#scanFile(android.content.Context, java.lang.String[], java.lang.String[], android.media.MediaScannerConnection.OnScanCompletedListener)
You could also call media scanner explicitly by sending broadcast.
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri
.parse("file://"
+ Environment.getExternalStorageDirectory())));
Edit
This was an old post. Updating it to new versions
Android is taking steps to prevent apps from spoofing more system broadcasts like this.
If you want to tell Android to index a file you put on external storage, either use MediaScannerConnection or ACTION_MEDIA_SCANNER_SCAN_FILE
Reference: This post
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
final Intent scanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
final Uri contentUri = Uri.fromFile(outputFile);
scanIntent.setData(contentUri);
sendBroadcast(scanIntent);
} else {
final Intent intent = new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStorageDirectory()));
sendBroadcast(intent);
}
If the above piece of code is not working you can try the following:
MediaScannerConnection.scanFile(this, new String[] {
file.getAbsolutePath()
}, null, new MediaScannerConnection.OnScanCompletedListener() {
#Override
public void onScanCompleted(String path, Uri uri) {
}
});
Here is another way to force scan:
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE,"uri to file"));
And then system will fire ACTION_MEDIA_SCANNER_FINISHED broadcast so you can react on it with BroadcastReceiver
In order to be able to receive ACTION_MEDIA_SCANNER_FINISHED broadcast, intent filter should contain data scheme:
IntentFilter intentFilter = new IntentFilter(Intent.ACTION_MEDIA_SCANNER_FINISHED);
intentFilter.addDataScheme("file");
context.registerReceiver(mMediaScannerFinishReceiver, intentFilter);
from the doc:
public static final String ACTION_MEDIA_SCANNER_SCAN_FILE
Added in API level 1 Broadcast Action: Request the media scanner to
scan a file and add it to the media database. The path to the file is
contained in the Intent.mData field.
and
public static final String ACTION_MEDIA_SCANNER_FINISHED
Added in API level 1 Broadcast Action: The media scanner has finished
scanning a directory. The path to the scanned directory is contained
in the Intent.mData field.
You can use MediaStore.Images.Media.insertImage to insert an item into the gallery.