2

I have an app that lets user choose music file from sdcard. To launch chooser intent I am using

    Intent intent = new Intent();
    intent.setType("audio/*");
    intent.setAction(Intent.ACTION_GET_CONTENT);
    startActivityForResult(
            Intent.createChooser(intent, "Complete action using"), 0);

But I am getting different absolute paths depending on what method user choose. If user uses ES File Explorer then I get /sdcard/Music/song.mp3 but if user uses some music app then I am getting /storage/sdcard0/Music/song.mp3. Its very confusing and my app requires me to know one final base path. Environment.getExternalStorageDirectory() returns /storage/sdcard0/. Any help would be appreciated.
Note: in both cases

    Uri uri = Uri.parse(new File(soundPath).getAbsolutePath()); 
    mPlayer = MediaPlayer.create(this, uri); 

works fine.

M-Wajeeh
  • 17,204
  • 10
  • 66
  • 103

2 Answers2

1

/sdcard is usually symlinked to the real(*) path in the filesystem (the /storage one) to stay compatible with early Android devices where /sdcard was the default.

Using Environment.getExternalStorageDirectory() is the method you should use. There is no guarantee that /sdcard or /storage/sdcard0 will work if you hardcode that path. Device manufacturers can use pretty much any filesystem layout they want but they will make sure that Environment knows the correct path.


(*) Starting Honeycomb & the "unified storage model" the real path is actually something like /data/media which is loop-mounted via fuse to /storage/sdcard0 (or whatever Environment tells you) to enforce the correct permission required for the WRITE_EXTERNAL_STORAGE permission.

Impromptu Q&A Session With Android Engineer Dan Morrill Brings To Light Reasons Behind Galaxy Nexus' Lack Of USB Mass Storage - second question has some details.


getAbsolutePath() is by the way not working in the same way as it does for desktop Java apps. On Android, the current working directory / root is always /. So getAbsolutePath() would always return the same as getPath() does and will at most prefix the path with a /.

Uris from File can be easily constructed via

Uri uri = Uri.fromFile(new File(soundPath));

that way you get a correct Uri using the file:// scheme which is not the case (and could lead to errors) if you use Uri.parse("/some/path")

zapl
  • 63,179
  • 10
  • 123
  • 154
  • So I guess if path starts with `/sdcard/` then I could just replace it with `Environment.getExternalStorageDirectory()` to ensure one final path. – M-Wajeeh Nov 20 '12 at 07:24
  • @M-WaJeEh If you really need to unify the paths you get yes. You could also try if `File#getCanonicalPath` can do that automatically for you. See http://stackoverflow.com/a/813726/995891 – zapl Nov 20 '12 at 08:16
1

Getting full path and file name:

 Private String getPath(Uri u) {
            String[] projection = { MediaStore.Audio.Media.DATA };
            Cursor cursor = managedQuery(u, projection, null, null, null);
            int column_index = cursor
                    .getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
            cursor.moveToFirst();
            return cursor.getString(column_index);
        }

use this on onActivityResult

String mpath = getPath(data.getData());

Prasanth S
  • 3,725
  • 9
  • 43
  • 75