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:

Douglas Farias

Expert
Licensed User
Longtime User
This code works on debug here, on the release have error on my MOTO G
 

Attachments

  • 10257254_807677449262473_504835715682912624_n.jpg
    10257254_807677449262473_504835715682912624_n.jpg
    46.4 KB · Views: 2,291

Douglas Farias

Expert
Licensed User
Longtime User
Erel how can i fix this error?
LogCat connected to: B4A-Bridge: motorola XT1033-359321054369100
--------- beginning of /dev/log/main
running waiting messages (1)
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = true **
** Activity (main) Create, isFirst = false **
** Activity (main) Resume **
** Service (service1) Destroy **
** Service (service1) Create **
** Service (service1) Start **
Connected to B4A-Bridge (Wifi)
Installing file.
** Activity (main) Pause, UserClosed = false **
PackageAdded: package:njdude.ocr.sample
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = true **
Installing file.
PackageAdded: package:njdude.ocr.sample
Installing file.
PackageAdded: package:njdude.ocr.sample
** Activity (main) Create, isFirst = true **
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = false **
** Activity (main) Resume **
** Activity (main) Pause, UserClosed = false **
sending message to waiting queue (OnActivityResult)
running waiting messages (1)
java.lang.IllegalArgumentException: Unknown column requested: _data
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:167)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:137)
at android.content.ContentProviderProxy.query(ContentProviderNative.java:413)
at android.content.ContentResolver.query(ContentResolver.java:461)
at android.content.ContentResolver.query(ContentResolver.java:404)
at anywheresoftware.b4a.objects.ContentResolverWrapper.Query(ContentResolverWrapper.java:43)
at njdude.ocr.sample.main._getpathfromcontentresult(main.java:704)
at njdude.ocr.sample.main._ocrgaleria_result(main.java:845)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:175)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:159)
at anywheresoftware.b4a.phone.Phone$ContentChooser$1.ResultArrived(Phone.java:843)
at anywheresoftware.b4a.BA$5.run(BA.java:505)
at anywheresoftware.b4a.BA.setActivityPaused(BA.java:390)
at njdude.ocr.sample.main$ResumeMessage.run(main.java:271)
at android.os.Handler.handleCallback(Handler.java:733)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:136)
at android.app.ActivityThread.main(ActivityThread.java:5086)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
at dalvik.system.NativeStart.main(Native Method)

I have this error sometimes, sometimes works fine can i select a image from chooser, sometimes give me this error
Moto G
 

alexb

Member
Licensed User
Longtime User
Is it possible to adapt the above SUB to find the actual file path for a GMAIL attachment ?

Example:
'Bundle[{android.intent.extra.STREAM=content://gmail-ls/[email protected]/messages/681/attachments/0.1/BEST/false}]

I am able to pass the UriString 'content://gmail-ls/mymail@gmail.com/messages/681/attachments/0.1/BEST/false' but for obvious reasons the SUB cannot handle it. I have no clue about the data structure, therefore I would not know how to modify the sub. Can anybody help? Thx!
(btw: this was for an image)

Note: I modified above sub and added following line because on my phone file browser intent (data) was preceded by 'file:/' :
If UriString.StartsWith("file:/") Then Return UriString.Replace("file:/","") 'If the user used a file manager to choose the image
 

alexb

Member
Licensed User
Longtime User
It is possible that there is no file at all, or that the file is not accessible.

However you can still open a stream to this resource and then copy it.

Erel. thank you for your reply

The file is shared correctly when I choose a different app such as another Email program where the photo is then displayed correctly(and with the original file name), so I must assume the data is valid.

I have tried to use File.OpenInput but was not successful with that either, I did not obtain a valid stream. The code looks like that:

Dim UriString As String
UriString ="content://gmail-ls/mymail@gmail.com/messages/681/attachments/0.1/BEST/false"
File.OpenInput("",UriString)

Do you consider this correct or is there a mistake with the arguments?

Btw: I had the same STREAM problem with File.OpenInput and type media "content://media/external/images/media", however for the media contents the above routine works fine, so I did not care. Maybe a full example would help that I do not make any stupid error . THANK YOU!
 

alexb

Member
Licensed User
Longtime User
Try this:
B4X:
Dim jo As JavaObject
jo = jo.InitializeStatic("anywheresoftware.b4a.objects.streams.File").GetField("ContentDir")
Dim UriString As String = "content://gmail...")
Dim in As InputStream = File.OpenInput(jo, UriString)
Erel, THANKS SO MUCH FOR YOUR OUTSTANDING SUPPORT!

It worked for me with following modification:
Dim jo As JavaObject
jo = jo.InitializeStatic("anywheresoftware.b4a.objects.streams.File").GetField("ContentDir")
Dim jo2 As Object
jo2 = jo
Dim In As InputStream = File.OpenInput(jo2, UriString)

I noticed the IDE complaint about string instead of object. Maybe because I am still using an older B4A version?
 

alexb

Member
Licensed User
Longtime User
It is better to write it this way:
B4X:
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)
Confirm - works too. Again, thanks a lot for all your help!
 

delozoya

Member
Licensed User
Longtime User
Helo. I have a problem. When I use GetPathFromContentResult It return null. This is code
B4X:
Sub CC_Result (Success As Boolean, Dir As String, FileName As String)
    If Success Then
    Log("filename: "&FileName)

        Dim normalizedFile As String = GetPathFromContentResult(FileName)
        Log("normalize : "&normalizedFile)
    '        CallSubDelayed3(FileTranser, "SendFile",Dir,normalizedFile)
           
    Else
        If LastException.IsInitialized Then ToastMessageShow(LastException.Message, True)
    End If
End Sub



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 Proj() As String
   Proj = Array As String("_data")
   Dim Cursor As Cursor
   Dim r As Reflector
   Dim Uri As Object
   Uri = r.RunStaticMethod("android.net.Uri", "parse", _
      Array As Object(UriString), _
      Array As String("java.lang.String"))
   r.Target = r.GetContext
   r.Target = r.RunMethod("getContentResolver")
   Cursor = r.RunMethod4("query", _
   Array As Object(Uri, Proj, Null, Null, Null), _
   Array As String("android.net.Uri", _
      "[Ljava.lang.String;", "java.lang.String", _
      "[Ljava.lang.String;", "java.lang.String"))
   Cursor.Position = 0
   Dim res As String
   res = Cursor.GetString("_data")
   Cursor.Close
   Return res
End Sub
 

delozoya

Member
Licensed User
Longtime User
Log's: - filename: content://com.android.externalstorage.documents/document/primary%3A1.wav
- normalize : null

Any Solution
 
Last edited:

Mark Zraik

Member
Licensed User
Longtime User
Top