10

For getting all images on an device I query the ContentResolver for MediaStore.Images. Now I want to add a option to show hidden files as well like many image apps like QuickPic do it.

Is there a faster way than recursively searching all directories on the phone and check if a .nomedia file is in it and if so, check if I can find some image file in it?

It's not possible through the ContentResolver is it?

prom85
  • 16,896
  • 17
  • 122
  • 242

2 Answers2

14

I am adding another Answer which is

  1. Lightning fast :- perform scanning in 134 microSeconds in my test App.
  2. Uses ContentResolver :- uses ContentResolver to scan all hidden Folders containing .noMedia file and then check if that folder have any Image file. You can modify code easily to return list of hidden image files as well.

I made a dummy app to test my code and here is output

You can see test App is showing WhatsApp's Sent Images folder have hidden images but at same time Video folder have none (as per requirement).

Hidden Images in whatsApp

How to do this

Problem can be divide into to parts

1) First of all with the help of content resolver get all Directories with .noMedia file in them . The code snippet below is self explanatory

private static final String FILE_TYPE_NO_MEDIA = ".nomedia";


/**
     * This function return list of hidden media files
     * 
     * @param context
     * @return list of hidden media files
     */
    private ArrayList<CustomFile> filterFiles(Context context) {

        ArrayList<CustomFile> listOfHiddenFiles = new ArrayList<CustomFile>();
        String hiddenFilePath;

        // Scan all no Media files
        String nonMediaCondition = MediaStore.Files.FileColumns.MEDIA_TYPE
                + "=" + MediaStore.Files.FileColumns.MEDIA_TYPE_NONE;

        // Files with name contain .nomedia
        String where = nonMediaCondition + " AND "
                + MediaStore.Files.FileColumns.TITLE + " LIKE ?";

        String[] params = new String[] { "%" + FILE_TYPE_NO_MEDIA + "%" };

        // make query for non media files with file title contain ".nomedia" as
        // text on External Media URI
        Cursor cursor = context.getContentResolver().query(
                MediaStore.Files.getContentUri("external"),
                new String[] { MediaStore.Files.FileColumns.DATA }, where,
                params, null);

        // No Hidden file found
        if (cursor.getCount() == 0) {

            listOfHiddenFiles.add(new CustomFile("No Hidden File Found",
                    "Nothing to show Here", "Nothing to show Here", false));

            // show Nothing Found
            return listOfHiddenFiles;
        }

        // Add Hidden file name, path and directory in file object
        while (cursor.moveToNext()) {
            hiddenFilePath = cursor.getString(cursor
                    .getColumnIndex(MediaStore.Files.FileColumns.DATA));
            if (hiddenFilePath != null) {

                listOfHiddenFiles
                        .add(new CustomFile(FileUtils
                                .getFileName(hiddenFilePath), hiddenFilePath,
                                FileUtils.getFileParent(hiddenFilePath),
                                isDirHaveImages(FileUtils
                                        .getFileParent(hiddenFilePath))));
            }
        }

        cursor.close();

        return listOfHiddenFiles;

    }

2) Now for second part of puzzle How to find if directory containing .noMedia file have hidden images in it.

Solution is use simple for loop to check if any of file in directory have image file extension(.jpg,.png etc), if that is true break the loop and set flag that, current directory have some hidden images in it.

Here instead of breaking for loop you can return list of images using function from my first Answer.**

/**
     * 
     * @param dir
     *            to serch in
     * @param fileType
     *            //pass fileType as a music , video, etc.
     * @return ArrayList of files of comes under fileType cataegory
     */
    public boolean isDirHaveImages(String hiddenDirectoryPath) {

        File listFile[] = new File(hiddenDirectoryPath).listFiles();

        boolean dirHaveImages = false;

        if (listFile != null && listFile.length > 0) {
            for (int i = 0; i < listFile.length; i++) {

                if (listFile[i].getName().endsWith(".png")
                        || listFile[i].getName().endsWith(".jpg")
                        || listFile[i].getName().endsWith(".jpeg")
                        || listFile[i].getName().endsWith(".gif")) {

                    // Break even if folder have a single image file
                    dirHaveImages = true;
                    break;

                }
            }
        }
        return dirHaveImages;

    }

Now back to your question

  • Is there a faster way than recursively searching all directories on
    the phone and check if a .nomedia file is in it?

    See code snippet 1

    -

and if so, check if I can find some image file in it?

See code snippet 2

  • It's not possible through the ContentResolver is it?

yes it is !!

I have uploade entire sample on Github, you can download and Modify as you wish

Hitesh Sahu
  • 41,955
  • 17
  • 205
  • 154
  • Just read it, I will test that, thank you very much. Sounds really great. Did not know that ' .nomedia` files are indexed and accessible via the `MediaStore`... – prom85 Jul 07 '16 at 19:24
  • it is not limited to .nomedia files. You can find all pdf files in similar manner just replace .nomedia with .pdf in constant. – Hitesh Sahu Jul 08 '16 at 05:34
  • I was aware of this... Just thought, that the media store is not indexing hidden files/folders at all... – prom85 Jul 08 '16 at 07:29
  • this still has a huge problem: when using the storage provider, listing files is really slow (near to unusable). So checking if a folder has an image in it does not work there... – prom85 Jul 16 '16 at 19:19
  • I have another problem with this solution I just realised: this solution does not respect, that all sub folders in a hidden folder are hidden as well. Do you have any idea how to handle this in a fast way? – prom85 Jul 29 '16 at 06:30
  • Let me check, I will reply soon. – Hitesh Sahu Jul 29 '16 at 07:01
  • There is another problem, folders who's name start with a dot are not respected as well... I've opened an issue on your demo project, any feedback, ideas or so is very appreciated – prom85 Oct 21 '16 at 05:57
  • @HiteshSahu Is it possible to load all the Images, Videos and Audios including the Media whose parent folder has `.nomedia` file. Can you please help. – Rahulrr2602 Jan 14 '18 at 21:03
  • 1
    @HiteshSahu just checked it on Android 10, it seems not working anymore. ContentResolver cannot find any ".nomedia" files anymore. Can you confirm it? – RuSsCiTy Oct 25 '19 at 14:36
  • 2
    Yes it is not working. Not able to find out images from hidden folders where .nomedia file is there. – Smeet May 17 '21 at 06:31
  • 1
    You can no longer access hidden files (like .nomedia and .thumbnails) on Android 10 and above – Atakan Yildirim Jan 27 '22 at 21:19
  • Only way to do it now is to request the user access to the folder – cmak Mar 11 '22 at 18:30
0

You can do iterative search on SD card for files in folders with extension of .nomedia

Here is the code snippet of function which return search result in an ArrayList of files card depending on input fileType.

  ArrayList<File> fileList = new ArrayList<File>();

    enum FileType {
        DOCUMENT,
        MUSIC,
        VIDEO,
        IMAGES,
        HIDDEN
    }

    /**
     * 
     * @param dir to serch in
     * @param fileType //pass fileType as a music , video, etc.
     * @return ArrayList of files of comes under fileType cataegory
     */
    public ArrayList<File> getAllFilesInDirectory(File dir, FileType fileType)
    {
        File listFile[] = dir.listFiles();

        if (listFile != null && listFile.length > 0) {
            for (int i = 0; i < listFile.length; i++) {
                if (listFile[i].isDirectory()) {
                    getAllFilesInDirectory(listFile[i], fileType);
                } else {

                    switch (fileType) {
                        case DOCUMENT:
                            if (listFile[i].getName().endsWith(".pdf") || listFile[i].getName().endsWith(".txt") ||
                                    listFile[i].getName().endsWith(".xml") || listFile[i].getName().endsWith(".doc") ||
                                    listFile[i].getName().endsWith(".xls") || listFile[i].getName().endsWith(".xlsx")) {
                                fileList.add(listFile[i]);
                            }

                            break;
                        case MUSIC:
                            if (listFile[i].getName().endsWith(".mp3")) {
                                fileList.add(listFile[i]);
                            }
                            break;

                        case VIDEO:
                            if (listFile[i].getName().endsWith(".mp4")) {
                                fileList.add(listFile[i]);
                            }
                            break;

                        case IMAGES:
                            if (listFile[i].getName().endsWith(".png") || listFile[i].getName().endsWith(".jpg")
                                    || listFile[i].getName().endsWith(".jpeg") || listFile[i].getName().endsWith(".gif")) {
                                fileList.add(listFile[i]);
                            }

                            break;

                        case HIDDEN:

                            if (listFile[i].getName().endsWith(".nomedia")) {
                                fileList.add(listFile[i]);
                            }
                            break;
                    }
                }
            }
        }

        return fileList;
    }

Beauty of this method is that it is not limited to search only hidden file. You can use same method to search all IMAGES, DOCUMENT,VIDEO & MUSIC files.

Hitesh Sahu
  • 41,955
  • 17
  • 205
  • 154
  • The problem with this apporach is the speed. You need to get ALL files of a folder and that's really slow... This is my current solution with a small performance optimisation (I query all visible folders from the media store and don't check visible folders, which is the only optimisation I have so far and I can think of) – prom85 Jul 07 '16 at 12:16
  • Added another answer with the help of content resolver – Hitesh Sahu Jul 07 '16 at 16:41
  • Can this method search whole storage of phone? If *yes* , can you please tell me what should i pass in `@param dir`. ? – karanatwal.github.io Mar 10 '17 at 17:16