Android Question Using Photos from the Phone

Shadow&Max

Active Member
Licensed User
Longtime 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:

mohsen nasrabady

Active Member
Licensed User
Longtime User
solved with this code
B4X:
Sub cs_Result (Success As Boolean, Dir As String, FileName As String)
If Success Then  
Dim fp As String = GetPathFromContentResult(FileName)
name = fp.SubString2(fp.LastIndexOf("/")+1,fp.Length)
path = fp.SubString2(0,fp.LastIndexOf("/"))
End If
End Sub
 
Upvote 0

DonManfred

Expert
Licensed User
Longtime User
Upvote 0

lymey

Active Member
Licensed User
Longtime 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.

Is it possible to get the path / or file from Google Dive also? I am using the content chooser to get a file, and the Uri string looks like:
B4X:
content://com.google.android.apps.docs.storage/document/acc%3D1%3Bdoc%3D3
I suppose the real question is - can you programmatically access a file on Google Drive using the content chooser?
 
Upvote 0

lymey

Active Member
Licensed User
Longtime User
You should be able to open an InputStream to this url.
I have never tried this before, and can't find a good example. But this is what I did:
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
   
If UriString.StartsWith("content://com.google.android.apps.docs.storage/document") Then
  Dim jo As JavaObject
  jo = jo.InitializeStatic("anywheresoftware.b4a.objects.streams.File").GetField("ContentDir")
   
  Dim In As InputStream = File.OpenInput(jo, UriString)
'the following to see if inputstream works:    
  Dim xbmp As Bitmap
  xbmp.Initialize2(In)
  pic.SetBackgroundImage(xbmp)
'need to save file (with the same file name displayed in Google Drive
End If
 
End Sub

and this is the error I got:
java.io.FileNotFoundException: /(String) ContentDir/content:/com.google.android.apps.docs.storage/document/acc%3D1%3Bdoc%3D3: open failed: ENOENT (No such file or directory)
Obviously I am doing something wrong! Something to do with the way the java object is initialized ...but I am in uncharted territory for me!

Also how do I resolve the filename from Google Drive using the content chooser?
 
Upvote 0

lymey

Active Member
Licensed User
Longtime User
Try this:
B4X:
Sub CC_Result (Success As Boolean, Dir As String, FileName As String)
If Success Then
  Dim in As InputStream = File.OpenInput(Dir, FileName)
  ...
End If
End Sub
That's great I can get the file content - thank you.
But how do I resolve the file name from Google Drive if I am using the content chooser?
 
Upvote 0

lymey

Active Member
Licensed User
Longtime User
This is what happens using Google Drive with the ContentChooser with the following code:
B4X:
Sub cc_Result (Success As Boolean, Dir As String, FileName As String)
    Log("Success = " & Success & ", Dir = " & Dir & ", FileName = " & FileName)
    Dim realPath As String = GetPathFromContentResult(FileName)
    Log("realPath = " & realPath)
    Activity.SetBackgroundImage(LoadBitmapSample("", realPath, 100%x, 100%y))
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 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

An error is generated at :
B4X:
 Cursor1 = cr.Query(Uri1, Proj, "", Null, "")
Error:
java.lang.IllegalArgumentException: Unknown column requested: _data
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:167)

This is the log generated by cc_result:
Success = true, Dir = ContentDir, FileName = content://com.google.android.apps.docs.storage/document/acc%3D1%3Bdoc%3D3

Any ideas on how to change GetPathFromContentResult?
 
Upvote 0

lymey

Active Member
Licensed User
Longtime User
This is what happens using Google Drive with the ContentChooser with the following code:

I did some poking around and found this: http://stackoverflow.com/questions/...i-android-kitkat-new-storage-access-framework
One of the suggestions to obtain the file name from Google Drive was to read '_display_name' from the cursor. So I altered the code:

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 Proj() As String = Array As String("_display_name")
  
   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")
   res = Cursor1.GetString("_display_name")
   Cursor1.Close
   Return res
End Sub

This now returns the correct file name when using the chooser to select a Google Drive file.
 
Upvote 0

mohsen nasrabady

Active Member
Licensed User
Longtime User
some times the sub
cs_Result (Success As Boolean, Dir As String, FileName As String)
return nothing and log is
onActivityResult: IOnActivityResult was released
what's the problem?
 
Upvote 0

little3399

Active Member
Licensed User
Longtime User
Hi, Erel
Does the 1.zip sample can be only show PhotoLibrary and not include the Files Manager ? TKs!
 
Upvote 0
Top