Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Preventing Media Scanner from Scanning JPGs Downloaded with the DownloadManager on Android? (Developer)

My application downloads jpgs from a website using DownloadManager and store them in the /sdcard/Android/name.app/ directory to be used in several Fragments in the application. The download works great however, the jpgs are visible in the Gallery application, which I don't want since they are just assets for my application. I cannot figure out how to have them not show up in the Gallery application. I even tried adding .nomedia files to the directories are they are created. Any help would be appreciated!

    DownloadManager myDownloadManager = (DownloadManager) myActivity.getSystemService(Context.DOWNLOAD_SERVICE);
    Request myRequest = new Request(Uri.parse(episodeArtLink));
    myRequest.setNotificationVisibility(Request.VISIBILITY_HIDDEN);
    myRequest.setVisibleInDownloadsUi(false);
    myRequest.setDestinationInExternalFilesDir(myActivity, Environment.DIRECTORY_DOWNLOADS, myFilename);
    myDownloadManager.enqueue(myRequest);

The issues seem to be caused because MediaScanner is adding the Images to the system database even though I have not asked it to.

I have created a test app that demonstrates the problem. If you click the Download button the Google logo will show up in the app. If you go into the Gallery app you should also see the Google logo in a gallery named Download. If you go to Settings -> Apps and Clear the Data for Gallery and Media Storage then the Google logo will be gone and won't show up again in Gallery because the file is under /sdcard/Android/data/ which is protected by the .nomedia file. You can go to /sdcard/Android/data/com.example.downloadmanagertest/files/Download/ to verify that the images are still on the phone. Even after a reboot the images don't show up in Gallery if you clear the Data for Gallery and Media Storage. I have tested this on both a Nexus 4 and a Nexus 7 running 4.2.2.

Source: https://dl.dropboxusercontent.com/u/114414/DownloadManagerTest.zip

like image 773
notkevin Avatar asked May 06 '13 03:05

notkevin


3 Answers

Solution

The media scanner will eventually sooner or later scan the media card for media and index them. The first intuitive step is to trick the Scanner into not knowing that the file is a media file. This can be achieved by saving the images without the extension. An easy solution would be to append notkevin to the end of the filename. Simply:

Instead of

 myRequest.setDestinationInExternalFilesDir(this, Environment.DIRECTORY_DOWNLOADS, Uri.parse(downloadLink).getLastPathSegment());

Use this

 String filename = Uri.parse(downloadLink).getLastPathSegment() + "notkevin";
 myRequest.setDestinationInExternalFilesDir(this, Environment.DIRECTORY_DOWNLOADS, filename);

However this is not sufficient in your case since you are using the DownloadManager (just a guess). The media scanner somehow knows about the downloaded item and the fact that it is an image and, thus, indexes it. To disallow it, use setMimeType like this:

myRequest.setMimeType("application/octet-stream");

PS: There are ways to change the extension other than adding your or my name to the end of the filename. For example, you could hash the filename

String filename = hash(Uri.parse(downloadLink).getLastPathSegment());

public String hash(String victim) throws NoSuchAlgorithmException
{
    MessageDigest md = MessageDigest.getInstance("SHA1");
    md.reset();
    byte[] buffer = victim.getBytes();
    md.update(buffer);
    byte[] digest = md.digest();

    StringBuilder hexStr = new StringBuilder();
    for (int i = 0; i < digest.length; i++) {
        hexStr.append(Integer.toString( ( digest[i] & 0xff ) + 0x100, 16).substring( 1 ));
    }
    return hexStr.toString();
}
like image 111
Sherif elKhatib Avatar answered Nov 03 '22 05:11

Sherif elKhatib


I've been at this same problem for a few days now. I've tried just about every combination of creating hidden directories, using different extensions, putting .nomedia files in root and image directories directories, creating the .nomedia before the download, renaming directory (back and forth).

Unfortunately none of these seems to work for me (on the Nexus 4). My understanding is that the MediaScanner only does a re-scan when booting the phone or mounting the external storage. In a Nexus 4 (or any device which has no SD card slot) this mounting only happens at boottime.

However files downloaded with the Android Download Manager are immediately scanned (even though they shouldn't be) and placed into the gallery. Even if you have the .nomedia file they still end in the gallery. Uninstalling the app doesn't help as they thumbnails are still cached (you can remove them without a reboot by clearing the cache, data and force closing the Gallery and Media Storage apps in settings). If you reboot the phone Android rescans the external storage, sees that there is a .nomedia file, and then removes it from the gallery.

So this reboot/rescan kinda fixes the problem. However we don't want to be constantly asking users to reboot the phone so instead what worked for me was to force Android to rescan the external storage after successful downloads with:

sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" +  Environment.getExternalStorageDirectory())));

Which I got from Darshan's answer to a similar question and Jon.

I setup a broadcast receiver to listen for completed downloads and if they are successful I send the broadcast. Seems to work - downloaded images in my app are no longer appearing in the gallery.

like image 43
Tim Avatar answered Nov 03 '22 04:11

Tim


You may also put your entire folder to be untouched by the Scanner without having a change in your file extensions. Please refer to the ".nomedia" file in this link;

Hiding your files from the Media Scanner

Include an empty file named .nomedia in your external files directory (note the dot prefix in the filename). This prevents media scanner from reading your media files and providing them to other apps through the MediaStore content provider. However, if your files are truly private to your app, you should save them in an app-private directory.

like image 34
stdout Avatar answered Nov 03 '22 04:11

stdout