Bug? [Solved] Trouble with External Storage Class

agraham

Expert
Licensed User
Longtime User
I am having trouble with the External Storage Class failing to remember the permission and asking every time the program calls 'SelectDir'.

This happens on more than one device and seems to be time related. After installation you get asked once to select the SD Card to give permission and then it works perfectly until one day it starts asking every time. Today I have had it happen on two different devices on both of which the program was installed about 14 days ago and have had it happen previously on other devices as well. The only way to stop this is to uninstall and reinstall the app.

I don't know much about the Storage Access Framework but Ghost Commander, for example, uses SAF to read and modify files on an external SD card, and I have never seen it ask again after the first time.

It's not a big deal for me as I now keep a copy of the app apk in one of the app's data folders and uninstalling and reinstalling it only takes a few seconds but it would be quite annoying if it happened to an app from the Play Store.
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
You will need to debug the code in SelectDir. The permission is managed by the OS.

Add some log messages to better understand why it doesn't work. This is the relevant code:
B4X:
PersistantUri = File.ReadString(File.DirInternal, FileName)
Dim list As List = ctxt.RunMethodJO("getContentResolver", Null).RunMethod("getPersistedUriPermissions", Null)
If list.IsInitialized Then
   For Each uripermission As JavaObject In list
       Dim u As Uri = uripermission.RunMethod("getUri", Null)
       Dim s As String = u 'ignore
       If s = PersistantUri And uripermission.RunMethod("isWritePermission", Null) = True Then
           Log("Can use persistant uri!")
           SetPickedDir
           Return
       End If
   Next
End If
 

agraham

Expert
Licensed User
Longtime User
By what mechanism is this code called to write the PersistantUri ?
B4X:
Private Sub ion_Event (MethodName As String, Args() As Object) As Object
   If Args(0) = -1 Then 'resultCode = RESULT_OK
       Dim i As Intent = Args(1)
       Dim jo As JavaObject = i
       Dim treeUri As Uri = jo.RunMethod("getData", Null)
       Dim takeFlags As Int = Bit.And(i.Flags, 3)
       ctxt.RunMethodJO("getContentResolver", Null).RunMethod("takePersistableUriPermission", Array(treeUri, takeFlags))
       PersistantUri = treeUri 'ignore
       File.WriteString(File.DirInternal, FileName, PersistantUri)
       Log(PersistantUri)
       SetPickedDir
   End If
   Return Null
 

agraham

Expert
Licensed User
Longtime User
One of my devices has got into the constantly asking external storage permission loop and I can see what is happening but not why :(

This Sub is writing the string
"(HierarchicalUri) content://com.android.externalstorage.documents/tree/3431-6431%3A"
to the "PersistantUri" file
B4X:
Private Sub ion_Event (MethodName As String, Args() As Object) As Object
    Log("OnActivityResult Args(0) = " & Args(0)) ' Debugging
    If Args(0) = -1 Then 'resultCode = RESULT_OK
        Dim i As Intent = Args(1)
        Dim jo As JavaObject = i
        Dim treeUri As Uri = jo.RunMethod("getData", Null)
        Dim takeFlags As Int = Bit.And(i.Flags, 3)
        ctxt.RunMethodJO("getContentResolver", Null).RunMethod("takePersistableUriPermission", Array(treeUri, takeFlags))
        PersistantUri = treeUri 'ignore
        File.WriteString(File.DirInternal, FileName, PersistantUri)
        Log("PersistantUri = " & PersistantUri)
        SetPickedDir
    End If
    Return Null
End Sub


But in this Sub the List returned from "getPersistedUriPermissions" contains
"(StringUri) content://com.android.externalstorage.documents/tree/3431-6431%3A"
Which doesn't match the string saved in the "PersistantUri" file so it tries again, and again, and again!
B4X:
Public Sub SelectDir (UsePreviouslySelectedIfAvaiable As Boolean)
    Log("Called SelectDir(" & UsePreviouslySelectedIfAvaiable &")") ' Debugging
    Log("File " & File.DirInternal & "," & FileName & " exists = " &  File.Exists(File.DirInternal, FileName)) ' Debugging
    If UsePreviouslySelectedIfAvaiable And File.Exists(File.DirInternal, FileName) Then
        PersistantUri = File.ReadString(File.DirInternal, FileName)
        Log("Using previous selection") ' Debugging
        Log("PersistantUri = " & PersistantUri) ' Debugging
        Dim list As List = ctxt.RunMethodJO("getContentResolver", Null).RunMethod("getPersistedUriPermissions", Null)
        If list.IsInitialized Then
            Log("List is initialised") ' Debuggiing
            For Each uripermission As JavaObject In list
                Dim u As Uri = uripermission.RunMethod("getUri", Null)
                Dim s As String = u 'ignore
                Log("PersistedUriPermissions = " & s & " | Write permission = " & uripermission.RunMethod("isWritePermission", Null)) ' Debugging|
                If s = PersistantUri And uripermission.RunMethod("isWritePermission", Null) = True Then
After uninstalling and reinstalling the app the List returned from "getPersistedUriPermissions" in SelectDir is
"(HierarchicalUri) content://com.android.externalstorage.documents/tree/3431-6431%3A"
which matches so all is well.

I think I will massage the returned and saved string to remove the leading parenthesized expression and see how that goes - unless a particular someone has a better suggestion!
 

agraham

Expert
Licensed User
Longtime User
To make it work I was replacing the different prefixes with
B4X:
Private Sub NormaliseUri(Uri As String) As String
    Dim idx As Int = Uri.IndexOf(")")
    Uri = Uri.SubString(idx+2)
    Return Uri
End Sub
And yes, with your code the stringified Uri now also lacks the problematic prefix, for reasons I don't understand as the generated Java looks similar!

I have replaced the "Dim s As String = u 'ignore" line in SelectDir as well with your code and hopefully it will now work without the problem recurring.
 
Top