Android Question Using Photos from the Phone

Shadow&Max

Active Member
Licensed User
OK, so I want to retrieve a photo from the phone... I use the ContentChooser to get the photo.

Now, I want to save the location of that picture in a file, and reload it at a later time.

I can GET the picture the first time... That's working. Then I save the Dir and FileName to variables that are saved in the file.

When I reload the file, I want to set an image control to that photo.

I'm getting a Security message when I try to access that file again:
java.lang.SecurityException: Permission Denial: opening provider com.android.providers.media.MediaDocumentsProvider from ProcessRecord{429c19b0 13253:com.twodogapps.gaa/u0a136} (pid=13253, uid=10136) requires android.permission.MANAGE_DOCUMENTS or android.permission.MANAGE_DOCUMENTS

The file dir and file name that are being saved are:
Dir: ContentDir
FileName: content://com.android.providers.media.documents/document/image%3A131

The ContentChooser is initialized, I'm pretty sure. I set the image like this:

iv.SetBackgroundImage(LoadBitmap(gs.listhere(Index).PhotoDir, gs.listhere(Index).PhotoFile))

In the above line, the index is correct and is getting the values above. As soon as it hits this line, I get the SecurityException shown above.

What am I doing wrong here?

Also, on my phone's permissions for the app it says:

  1. Modify or delete the contents of your USB storage
  2. full network access
  3. access Bluetooth settings - Pair with Bluetooth devices
  4. read the contents of your USB storage.
As far as I can tell those are all I need in terms of permissions.

I don't want to save the file in my apps database because they're just too big and no need to waste duplicate space.
 
Last edited:

Shadow&Max

Active Member
Licensed User
Hi Erel... Doesn't work... I copied and pasted the GetPathFromContentResult sub to my project, ran it, and immediately error out with basically the same error as above... Permission Denied.

This is on a Motorola Moto-X .

I get the same (almost the same error) on the:

B4X:
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"))
This is the error:
java.lang.SecurityException: Permission Denial: opening provider com.android.providers.media.MediaDocumentsProvider from ProcessRecord{42076d20 4861:com.twodogapps.gaa/u0a136} (pid=4861, uid=10136) requires android.permission.MANAGE_DOCUMENTS or android.permission.MANAGE_DOCUMENTS

Again, the variables I get back after selecting the photo are:

The file dir and file name that are being saved are:
Dir: ContentDir
FileName: content://com.android.providers.media.documents/document/image%3A131

My call to GetPathFromContentResult is:
iv.SetBackgroundImage(LoadBitmap("", GetPathFromContentResult(gs.slist(Index).PhotoFile)))

Where gs.slist(Index).PhotoFile is the FileName above (iv is an imageview)

Now, I'm not getting the permissions error, but the program errors out trying to return res, which is null...
 
Last edited:

Shadow&Max

Active Member
Licensed User
Yes Erel... My phone is a new Moto-X and it's running 4.4. I'll try adding the line to the manifest and see what happens... haven't messed with the manifest file before, but I'll give it a whack... Be back in a few to report back...
 

Shadow&Max

Active Member
Licensed User
Nope... Same thing... Didn't work... What's next??? :(

I really need to get this to work.

Is there any other way to extract the exact location of that file? What I don't understand is that I can read it with the cc.Show, and can choose the file and even assign it to the imageview after the cc.show. So I'm obviously being allowed to get there to view them and even display it. But when I try to read from them directly, it violates the permissions. Doesn't make sense.
 
Last edited:

Shadow&Max

Active Member
Licensed User
Will there be a fix for this at some point? If this is a KitKat thing, it's imperative that it get into B4A at some point fairly soon... KitKat's all over the place now.
 

jsanchezc

Member
Licensed User
Will there be a fix for this at some point? If this is a KitKat thing, it's imperative that it get into B4A at some point fairly soon... KitKat's all over the place now.
I copy image from chooser to dirdefaultexternal

I solved doing this:
B4X:
Sub chooser_Result (Success As Boolean, Dir As String, FileName As String)
  If Success Then
 
      Try
      File.Copy(Dir ,FileName,file.DirDefaultExternal ,"myfilename.jpg"  )
        PanelImage.SetBackgroundImage( LoadBitmap(file.DirDefaultExternal ,"myfilename.jpg"))
      Catch
         Log(LastException.Message)
    End Try     
 
  End If
End Sub
 

Shadow&Max

Active Member
Licensed User
Thanks! It's a great solution... the only problem I see is that I'm trying to avoid bloat... my phone takes 10MP shots... if a user save 20 of them in the app, that's a 200MB overhead that's doubled because the pictures are already in the media store on the phone. I suppose I could also resize and shrink them down so that they're not bigger than the biggest tablet out there in terms of size and resolution. The resolution may not be THAT important either... but if I save 200MB of photos, it'll make some users pretty grumpy I would think!

I may use this though... I'll try it first and see if it gets around KitKat's issues...

Thanks again!
 

Erel

Administrator
Staff member
Licensed User
You can use this code to get the full path (if such is available):
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
It depends on the following libraries: ContentResolver, SQL and Phone.
 
Last edited:

Gregg Homan

Member
Licensed User
Erel,

The new version of GetPathFromContentResult() is now throwing errors for both content://media... and content://com.android... uri formats. Note that the older version of GetPathFromContentResult() worked for the content://media... uri format but threw an error for the content://com.android... uri format.

I ran the test below on a Droid Maxx running Android V4.4. Also, I don't remember running into this problem with the content://com.android... uri format until after upgrading my phone to V4.4, but, I am not 100% certain of this.

Thanks,
Gregg

GetPathFromContentResult("content://com.android.providers.media.documents/document/image%3a7567") and
GetPathFromContentResult("content://media/external/images/media/7567") both error out on following line of code within GetPathFromContentResult():
B4X:
res = Cursor1.GetString("_data")
GetPathFromContentResult("content://com.android.providers.media.documents/document/image%3a7567") and
GetPathFromContentResult("content://media/external/images/media/7567") both throw the following identical error:
B4X:
android.database.CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0
    at android.database.AbstractCursor.checkPosition(AbstractCursor.java:426)
    at android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:136)
    at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:50)
    at android.database.CursorWrapper.getString(CursorWrapper.java:114)
    at anywheresoftware.b4a.sql.SQL$CursorWrapper.GetString(SQL.java:355)
    at Ovinion.Ovinion.main._getpathfromcontentresult(main.java:3145)
    at Ovinion.Ovinion.main._chooser_result(main.java:1832)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:515)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:173)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:157)
    at anywheresoftware.b4a.phone.Phone$ContentChooser$1.ResultArrived(Phone.java:843)
    at anywheresoftware.b4a.BA$4.run(BA.java:477)
    at anywheresoftware.b4a.BA.setActivityPaused(BA.java:388)
    at Ovinion.Ovinion.main$ResumeMessage.run(main.java:252)
    at android.os.Handler.handleCallback(Handler.java:733)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:5083)
    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:777)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:593)
    at dalvik.system.NativeStart.main(Native Method)
 

Gregg Homan

Member
Licensed User
Erel,
I replaced code line are suggested above; and, now GetPathFromContentResult() is throwing different errors for the two different uri formats.
Gregg

GetPathFromContentResult("content://media/external/images/media/7567") errors on following line and throws error below:
B4X:
res = Cursor1.GetString("_data")
B4X:
android.database.CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0
    at android.database.AbstractCursor.checkPosition(AbstractCursor.java:426)
    at android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:136)
    at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:50)
    at android.database.CursorWrapper.getString(CursorWrapper.java:114)
    at anywheresoftware.b4a.sql.SQL$CursorWrapper.GetString(SQL.java:355)
    at Ovinion.Ovinion.main._getpathfromcontentresult(main.java:3145)
    at Ovinion.Ovinion.main._chooser_result(main.java:1832)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:515)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:173)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:157)
    at anywheresoftware.b4a.phone.Phone$ContentChooser$1.ResultArrived(Phone.java:843)
    at anywheresoftware.b4a.BA$4.run(BA.java:477)
    at anywheresoftware.b4a.BA.setActivityPaused(BA.java:388)
    at Ovinion.Ovinion.main$ResumeMessage.run(main.java:252)
    at android.os.Handler.handleCallback(Handler.java:733)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:5083)
    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:777)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:593)
    at dalvik.system.NativeStart.main(Native Method)
GetPathFromContentResult("content://com.android.providers.media.documents/document/image%3a7567") errors on following line and throws error below:
B4X:
Cursor1 = cr.Query(Uri1, Proj, Null, Null, Null)
B4X:
java.lang.SecurityException: Permission Denial: reading com.android.providers.media.MediaDocumentsProvider uri content://com.android.providers.media.documents/document/image%3a7567 from pid=7601, uid=10229 requires android.permission.MANAGE_DOCUMENTS, or grantUriPermission()
    at android.os.Parcel.readException(Parcel.java:1461)
    at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:185)
    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 Ovinion.Ovinion.main._getpathfromcontentresult(main.java:3135)
    at Ovinion.Ovinion.main._chooser_result(main.java:1832)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:515)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:173)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:157)
    at anywheresoftware.b4a.phone.Phone$ContentChooser$1.ResultArrived(Phone.java:843)
    at anywheresoftware.b4a.BA$4.run(BA.java:477)
    at anywheresoftware.b4a.BA.setActivityPaused(BA.java:388)
    at Ovinion.Ovinion.main$ResumeMessage.run(main.java:252)
    at android.os.Handler.handleCallback(Handler.java:733)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:5083)
    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:777)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:593)
    at dalvik.system.NativeStart.main(Native Method)
 

barx

Well-Known Member
Licensed User
I made a little library to do this not so long ago. You can try it if you like.
 

Attachments

Gregg Homan

Member
Licensed User
Barx,

Thanks for your help. I am not sure what I am doing wrong for I thought following code should have worked but I am getting compiler error shown below.

Thanks,
Gregg

B4X:
Dim fn As String
Dim uri1 As Uri
Dim ut As uriTools   'Requires lib UriTools Verion 1.0 by Barx
uri1.Parse("content://com.android.providers.media.documents/document/image%3a7567")
fn = ut.getRealPathFromURI(uri1)
Compiler error:
B4X:
Parsing code.                          0.33
Compiling code.                        0.40
Compiling layouts code.                0.07
Generating R file.                      0.63
Compiling generated Java code.          Error
B4A line: 1225
fn = ut.getRealPathFromURI(uri1)
javac 1.7.0_25
src\Ovinion\Ovinion\main.java:1843: error: getRealPathFromURI(BA,Uri) has private access in uriTools
_fn = _ut.getRealPathFromURI(processBA,(android.net.Uri)(_uri1.getObject()));Debug.locals.put("fn", _fn);
 

barx

Well-Known Member
Licensed User
2 mins I will check the lib code.
 

barx

Well-Known Member
Licensed User
My Bad, you are correct. I have only ever used the other method which then in turn calls this one as and when required. Surprised it even shown in b4a.

Anyways, try this one. Made the method public.
 

Attachments

Gregg Homan

Member
Licensed User
Barx,

getRealPathFromURI() throws same error below as Erel's GetPathFromContentResult() when processing content://com.android... uri formats but both subroutines appear to handle content://media... uri formats OK. There seems to be some form of permissions issue. BTW, adding AddPermission("android.permission.MANAGE_DOCUMENTS") to the manifest file does not help either; and, I don't know how to implement grantUriPermision() as stated in first line of error message below. Do you have any additional ideas?

Gregg

B4X:
Dim fn As String
Dim uri1 As Uri
Dim ut As uriTools

uri1.Parse("content://media/external/images/media/7567")
fn = ut.getRealPathFromURI(uri1) 'WORKS

uri1.Parse("content://com.android.providers.media.documents/document/image%3a7567")
fn = ut.getRealPathFromURI(uri1) 'FAILS
Error thrown when processing content://com.android... uri formats:
B4X:
java.lang.SecurityException: Permission Denial: reading com.android.providers.media.MediaDocumentsProvider uri content://com.android.providers.media.documents/document/image%3a7567 from pid=7311, uid=10229 requires android.permission.MANAGE_DOCUMENTS, or grantUriPermission()
    at android.os.Parcel.readException(Parcel.java:1461)
    at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:185)
    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 barxdroid.uritools.uriTools.getRealPathFromURI(uriTools.java:54)
    at Ovinion.Ovinion.main._chooser_result(main.java:1859)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:515)
    at anywheresoftware.b4a.BA.raiseEvent2(BA.java:173)
    at anywheresoftware.b4a.BA.raiseEvent(BA.java:157)
    at anywheresoftware.b4a.phone.Phone$ContentChooser$1.ResultArrived(Phone.java:843)
    at anywheresoftware.b4a.BA$4.run(BA.java:477)
    at anywheresoftware.b4a.BA.setActivityPaused(BA.java:388)
    at Ovinion.Ovinion.main$ResumeMessage.run(main.java:252)
    at android.os.Handler.handleCallback(Handler.java:733)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:5083)
    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:777)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:593)
    at dalvik.system.NativeStart.main(Native Method)
 

barx

Well-Known Member
Licensed User
this is interesting as an app that i have been working on that uses this works fine on a nexus 7 running kitkat.....

edit: on the other hand, I get the uri's from an intent Extras
 
Top