Android Code Snippet Get the path to media files returned from ContentChooser

It is a mistake to try to get a file path from the returned resource. It will not work in most cases, and even if you will be able to get the path, you will not be able to access it.
You can use File.OpenInput to access the remote resource.

Correct solution: [B4X] TextEditor - Save and load external files
SubName: GetPathFromContentResult

Description: Content providers such as the media gallery return a URL that starts with content://...

If you are just interested in showing the selected image then you can use File.OpenInput to open an input stream. You can also use it together with File.Copy2 to copy the media to a new location.

With the following code you can find the actual file path (if it is available):
This code depends on ContentResolver and SQL libraries.
B4X:
Sub GetPathFromContentResult(UriString As String) As String
  If UriString.StartsWith("/") Then Return UriString 'If the user used a file manager to choose the image
  Dim Cursor1 As Cursor
  Dim Uri1 As Uri
  Dim Proj() As String = Array As String("_data")
  Dim cr As ContentResolver
  cr.Initialize("")
  If UriString.StartsWith("content://com.android.providers.media.documents") Then
  Dim i As Int = UriString.IndexOf("%3A")
  Dim id As String = UriString.SubString(i + 3)
  Uri1.Parse("content://media/external/images/media")
  Cursor1 = cr.Query(Uri1, Proj, "_id = ?", Array As String(id), "")
  Else
  Uri1.Parse(UriString)
  Cursor1 = cr.Query(Uri1, Proj, "", Null, "")
  End If
  Cursor1.Position = 0
  Dim res As String
  res = Cursor1.GetString("_data")
  Cursor1.Close
  Return res
End Sub

In most cases it is a mistake to use this sub. Especially in newer versions of Android. You shouldn't assume that the resource returned from ContentChooser comes from the file system and if it is, you most probably won't have permissions to directly access it.
 
Last edited:

pesquera

Active Member
Licensed User
Longtime User
Code:
Sub glo_ContentChooser_Result (Success AsBoolean, Dir AsString, FileName AsString)
If Success Then
Dim
jo As JavaObject
Dim cd As String = jo.InitializeStatic("anywheresoftware.b4a.objects.streams.File").GetField("ContentDir")
Dim UriString As String = "content://gmail..."
Dim In As InputStream = File.OpenInput(cd , UriString)
Hi Erel, I need to copy an image file (photo) to my app folder with File.Copy2..
I have this error:
An error has occured in sub: javai.io.FileNotFoundException: no content provider: /storage/emulated/0/DCIM/Camera/20150222_204549.jpg
with this code:
B4X:
Sub glo_ContentChooser_Result (Success AsBoolean, Dir AsString, FileName AsString)
If Success Then

Dim jo As JavaObject
Dim cd As String = jo.InitializeStatic("anywheresoftware.b4a.objects.streams.File").GetField("ContentDir")
Dim UriString As String = GetPathFromContentResult(FileName)
Dim In As InputStream = File.OpenInput(cd , UriString)     
...
Can you tell me what I'm doing wrong? I've just replaced the line that gets the file
Watching on the UriString Variable, I can see this value:
/storage/emulated/0/DCIM/Camera/20150222_204549.jpg
Isn't that value correct?
Thanks
 
Last edited:

driesvp

Member
Licensed User
Longtime User
When using "GetPathFromContentResult" I receive an error on the line "Cursor1.Position = 0". The error states that Cursor1 should be initialised first.
How to solve this?
 

walterf25

Expert
Licensed User
Longtime User
SubName: GetPathFromContentResult

Description: Content providers such as the media gallery return a URL that starts with content://...

If you are just interested in showing the selected image then you can use File.OpenInput to open an input stream. You can also use it together with File.Copy2 to copy the media to a new location.

With the following code you can find the actual file path (if it is available):
This code depends on ContentResolver and SQL libraries.
B4X:
Sub GetPathFromContentResult(UriString As String) As String
  If UriString.StartsWith("/") Then Return UriString 'If the user used a file manager to choose the image
  Dim Cursor1 As Cursor
  Dim Uri1 As Uri
  Dim Proj() As String = Array As String("_data")
  Dim cr As ContentResolver
  cr.Initialize("")
  If UriString.StartsWith("content://com.android.providers.media.documents") Then
  Dim i As Int = UriString.IndexOf("%3A")
  Dim id As String = UriString.SubString(i + 3)
  Uri1.Parse("content://media/external/images/media")
  Cursor1 = cr.Query(Uri1, Proj, "_id = ?", Array As String(id), "")
  Else
  Uri1.Parse(UriString)
  Cursor1 = cr.Query(Uri1, Proj, "", Null, "")
  End If
  Cursor1.Position = 0
  Dim res As String
  res = Cursor1.GetString("_data")
  Cursor1.Close
  Return res
End Sub

Tags: ContentChooser, file path
Hi All, i'm writing an Email application, i need to be able to attach any type of files when sending new emails or replying, i've tested Erel's code here but this only seems to work with image files, can anyone help me figure out how to get the full file path for let's say a pdf file or a text file, or even a zip file?

Thanks all in advanced.
Regards,
Walter
 

walterf25

Expert
Licensed User
Longtime User
Please start a new thread for this question.
Never mind, i created a small library from some code i found online that takes care of this problem, i will post it soon.

Regards,
Walter
 

Inman

Well-Known Member
Licensed User
Longtime User
SubName: GetPathFromContentResult

Description: Content providers such as the media gallery return a URL that starts with content://...

If you are just interested in showing the selected image then you can use File.OpenInput to open an input stream. You can also use it together with File.Copy2 to copy the media to a new location.

With the following code you can find the actual file path (if it is available):
This code depends on ContentResolver and SQL libraries.
B4X:
Sub GetPathFromContentResult(UriString As String) As String
  If UriString.StartsWith("/") Then Return UriString 'If the user used a file manager to choose the image
  Dim Cursor1 As Cursor
  Dim Uri1 As Uri
  Dim Proj() As String = Array As String("_data")
  Dim cr As ContentResolver
  cr.Initialize("")
  If UriString.StartsWith("content://com.android.providers.media.documents") Then
  Dim i As Int = UriString.IndexOf("%3A")
  Dim id As String = UriString.SubString(i + 3)
  Uri1.Parse("content://media/external/images/media")
  Cursor1 = cr.Query(Uri1, Proj, "_id = ?", Array As String(id), "")
  Else
  Uri1.Parse(UriString)
  Cursor1 = cr.Query(Uri1, Proj, "", Null, "")
  End If
  Cursor1.Position = 0
  Dim res As String
  res = Cursor1.GetString("_data")
  Cursor1.Close
  Return res
End Sub

Tags: ContentChooser, file path

The code is crashing when testing on Android 7.0. Tested uri was (HierarchicalUri) content://com.android.externalstorage.documents/tree/primary%3ADCIM. URI was obtained with the code given here.
B4X:
Error occurred on line: 222 (Test)

java.lang.RuntimeException: Object should first be initialized (Cursor).
    at anywheresoftware.b4a.AbsObjectWrapper.getObject(AbsObjectWrapper.java:50)
    at anywheresoftware.b4a.sql.SQL$CursorWrapper.getRowCount(SQL.java:335)
    at b4a.chrjak.sdcard.test._getpathfromcontentresult(test.java:661)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:710)
    at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:339)
    at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:249)
    at java.lang.reflect.Method.invoke(Native Method)
    at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:139)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:170)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:166)
    at anywheresoftware.b4a.objects.ViewWrapper$1.onClick(ViewWrapper.java:80)
    at android.view.View.performClick(View.java:5610)
    at android.view.View$PerformClick.run(View.java:22265)
    at android.os.Handler.handleCallback(Handler.java:751)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:154)
    at android.app.ActivityThread.main(ActivityThread.java:6077)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:866)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:756)
** Service (starter) Destroy **
 
Top