2

I want to know how to fetch all PDF files from internal storage. Files can be in any directory, like some in DCIM folders or some in Downloads folder, and so on and so forth.

Note: I am using Android Studio (language: Java).

Ryan M
  • 18,333
  • 31
  • 67
  • 74
Knowledge hub
  • 51
  • 1
  • 8
  • 1
    Get the root directory via new File(). File class affords also a listFile() method. Use it to get all files inside a folder. Enjoy with recursion and pay attention, it may cause lag!!! Now you should check if every file is a .pdf, do it checking if the file name contains ".pdf" extension via String#contains(). For every pdf file you found, save it inside a File array. Remember that you could catch some problems due to security of a linux kernel (Android is based on), so sure you won't able to check some folders... – DynoZ Feb 24 '21 at 16:30
  • 1
    Or try what [Shay Kin](https://stackoverflow.com/users/7085389/shay-kin) said. I've never used MediaStore, yet – DynoZ Feb 24 '21 at 16:31
  • 1
    @DynoZ your suggested solution [won't work on newer Android versions](https://stackoverflow.com/a/58379655/208273). – Ryan M Feb 25 '21 at 04:33

3 Answers3

4

i have search almost all the ans but it was not working in Android 11. so i have a short solution for picking up all file for example image, video, pdf, doc, audio etc. there was a github library which was recently created

Click [here] https://github.com/HBiSoft/PickiT

and if you want to do all this without dependency

Code Below

  • do it in orderwise

var mimeTypes = arrayOf(
    "application/msword",
    "application/vnd.openxmlformats-officedocument.wordprocessingml.document",  // .doc & .docx
    "application/vnd.ms-powerpoint",
    "application/vnd.openxmlformats-officedocument.presentationml.presentation",  // .ppt & .pptx
    "application/vnd.ms-excel",
    "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",  // .xls & .xlsx
    "application/pdf"
)

 findViewById<Button>(R.id.btnclick).setOnClickListener {

        val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
            addCategory(Intent.CATEGORY_OPENABLE)
            type = "*/*"
            putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);

            // mimeTypes = mimeTypes
        }

        startActivityForResult(intent, 100)

    }

 override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
    super.onActivityResult(requestCode, resultCode, data)
    Log.e(">>>>>>", "check")

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        getFile(this,intentToDocumentFiles(data)[0])
    }
}

 private fun intentToDocumentFiles(intent: Intent?): List<DocumentFile> {
    val uris = intent?.clipData?.run {
        val list = mutableListOf<Uri>()
        for (i in 0 until itemCount) {
            list.add(getItemAt(i).uri)
        }
        list.takeIf { it.isNotEmpty() }
    } ?: listOf(intent?.data ?: return emptyList())

    return uris.mapNotNull { uri ->
        if (uri.isDownloadsDocument && Build.VERSION.SDK_INT < 28 && uri.path?.startsWith("/document/raw:") == true) {
            val fullPath = uri.path.orEmpty().substringAfterLast("/document/raw:")
            DocumentFile.fromFile(File(fullPath))
        } else {
            fromSingleUri(uri)
        }
    }.filter { it.isFile }
}

@RequiresApi(Build.VERSION_CODES.R)
fun getFile(context: Context, document: DocumentFile): File? {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
        return null
    }
    try {
        val volumeList: List<StorageVolume> = context
            .getSystemService(StorageManager::class.java)
            .getStorageVolumes()
        if (volumeList == null || volumeList.isEmpty()) {
            return null
        }

        // There must be a better way to get the document segment
        val documentId = DocumentsContract.getDocumentId(document.uri)
        val documentSegment = documentId.substring(documentId.lastIndexOf(':') + 1)
        for (volume in volumeList) {
            val volumePath: String
            if (Build.VERSION.SDK_INT == Build.VERSION_CODES.Q) {
                val class_StorageVolume = Class.forName("android.os.storage.StorageVolume")
                val method_getPath: Method = class_StorageVolume.getDeclaredMethod("getPath")
                volumePath=method_getPath.invoke(volume).toString()
            } else {
                // API 30
                volumePath=volume.directory!!.path
            }
            val storageFile = File(volumePath + File.separator + documentSegment)

            // Should improve with other checks, because there is the
            // remote possibility that a copy could exist in a different
            // volume (SD-card) under a matching path structure and even
            // same file name, (maybe a user's backup in the SD-card).
            // Checking for the volume Uuid could be an option but
            // as per the documentation the Uuid can be empty.
            val isTarget = (storageFile.exists()
                    && storageFile.lastModified() == document.lastModified()
                    && storageFile.length() == document.length())
            if (isTarget) {
                Log.e(">>>>>>>",storageFile.absolutePath)
                return storageFile
            }
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
    Log.e(">>>>>>>","null")
    return null
}
Anil Dhiman
  • 1,011
  • 1
  • 4
  • 6
  • 1
    Thank you @Anil Dhiman, using the https://github.com/HBiSoft/PickiT library works for me. – Chidi Apr 06 '22 at 10:34
3

You can use MediaStore to fetch all PDF Files ,this is an example how to get all your PDF files :

   protected ArrayList<String> getPdfList() {
    ArrayList<String> pdfList = new ArrayList<>();
    Uri collection;

    final String[] projection = new String[]{
            MediaStore.Files.FileColumns.DISPLAY_NAME,
            MediaStore.Files.FileColumns.DATE_ADDED,
            MediaStore.Files.FileColumns.DATA,
            MediaStore.Files.FileColumns.MIME_TYPE,
    };

    final String sortOrder = MediaStore.Files.FileColumns.DATE_ADDED + " DESC";

    final String selection = MediaStore.Files.FileColumns.MIME_TYPE + " = ?";

    final String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension("pdf");
    final String[] selectionArgs = new String[]{mimeType};

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        collection = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL);
    }else{
        collection = MediaStore.Files.getContentUri("external");
    }


    try (Cursor cursor = getContentResolver().query(collection, projection, selection, selectionArgs, sortOrder)) {
        assert cursor != null;

        if (cursor.moveToFirst()) {
            int columnData = cursor.getColumnIndex(MediaStore.Files.FileColumns.DATA);
            int columnName = cursor.getColumnIndex(MediaStore.Files.FileColumns.DISPLAY_NAME);
            do {
                pdfList.add((cursor.getString(columnData)));
                Log.d(TAG, "getPdf: " + cursor.getString(columnData));
                //you can get your pdf files
            } while (cursor.moveToNext());
        }
    }
    return pdfList;
}
Shay Kin
  • 2,539
  • 3
  • 15
  • 22
0

This is improvised answer of @Shay Kin.

As we know in latest android versions we have many restrictions to access files in external storage.

MediaStore api and Storage Access Framework apis provides access to shared files. This is explained clearly in this video.

Coming to the answer, in Shay Kin's answer we can able to fetch all pdf files which are there in the shared files but ignores downloads.

Permissions required

READ_EXTERNAL_STORAGE

if api is Q plus you also need MANAGE_EXTERNAL_STORAGE

please find the below code to fetch all pdf files.

protected List<String> getPdfList() {
    List<String> pdfList = new ArrayList<>();

    final String[] projection = new String[]{
            MediaStore.Files.FileColumns.DISPLAY_NAME,
            MediaStore.Files.FileColumns.DATE_ADDED,
            MediaStore.Files.FileColumns.DATA,
            MediaStore.Files.FileColumns.MIME_TYPE,
    };

    final String sortOrder = MediaStore.Files.FileColumns.DATE_ADDED + " DESC";

    final String selection = MediaStore.Files.FileColumns.MIME_TYPE + " = ?";

    final String mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension("pdf");
    final String[] selectionArgs = new String[]{mimeType};
    
    Uri collection = MediaStore.Files.getContentUri("external");
    pdfList.addAll(getPdfList(collection, projection, selection, selectionArgs, sortOrder));

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        collection = MediaStore.Downloads.getContentUri("external");
        pdfList.addAll(getPdfList(collection,projection, selection, selectionArgs, sortOrder));
    }
    
    return pdfList;
}

private List<String> getPdfList(Uri collection, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
    List<String> pdfList = new ArrayList<>();

    try (Cursor cursor = getContentResolver().query(collection, projection, selection, selectionArgs, sortOrder)) {
        assert cursor != null;

        if (cursor.moveToFirst()) {
            int columnData = cursor.getColumnIndex(MediaStore.Files.FileColumns.DATA);
            do {
                pdfList.add((cursor.getString(columnData)));
                Log.d(TAG, "getPdf: " + cursor.getString(columnData));
                //you can get your pdf files
            } while (cursor.moveToNext());
        }
    }
    return pdfList;
}

Hope this works.

shobhan
  • 1,460
  • 2
  • 14
  • 28