Search code examples
androidmtpstorage-access-framework

Storage Access Framework does not update MediaScanner (MTP)


Using the SAF provided in KitKat, the MediaScanner is not called on files saved to the internal or external storage points of a device. As such I have to determine based on the returned URI if I should attempt to run MediaScanner.

// The SAF uses content URI to pass meta about the file. The following host is used for internal storage.
if (mExportServiceUri.getHost().equals("com.android.externalstorage.documents")) {
    final File externalStorage = Environment.getExternalStorageDirectory();
    final String path = mExportServiceUri.getEncodedPath().replace("/document/primary%3A", "");
    MediaScannerConnection.scanFile(mService.getApplicationContext(), new String[] { new File(
            externalStorage, path).getAbsolutePath() }, null, null);
}

Has anyone else had to work around this issue and if so, is there a better approach than this? Currently this only supports the device external storage and additional storage space such as the SDCard need to be handled in a separate check.


Solution

  • To support what I believe to be all possible mounts including USB thumb drives connected via OTG or even possibly directly to the full size usb port on some tablets (I dont have a tablet to test that with, does a 4.4 tablet even exist with a full size port?) I have the following which seems to work well on a Galaxy S4 (Play store edition) and a N5.

    // The SAF uses content URI to pass meta about the file. The following host is used for SD storage.
    if (mExportServiceUri.getHost().equals("com.android.externalstorage.documents")) {
        final String encodedPath = mExportServiceUri.getEncodedPath();
        final String path = encodedPath.substring(encodedPath.indexOf("%3A") + 3);
        final File[] storagePoints = new File("/storage").listFiles();
    
        // document/primary is in /storage/emulated/legacy and thus will fail the exists check in the else handling loop check
        if (encodedPath.startsWith("/document/primary")) {
            // External file stored in Environment path
            final File externalFile = new File(Environment.getExternalStorageDirectory(), path);
            MediaScannerConnection.scanFile(mService.getApplicationContext(),
                    new String[] { externalFile.getAbsolutePath() }, null, null);
        } else {
            // External file stored in one of the mount points, check each mount point for the file
            for (int i = 0, j = storagePoints.length; i < j; ++i) {
                final File externalFile = new File(storagePoints[i], path);
                if (externalFile.exists()) {
                    MediaScannerConnection.scanFile(mService.getApplicationContext(),
                            new String[] { externalFile.getAbsolutePath() }, null, null);
                    break;
                }
            }
        }
    }