Android Question Open File From Folder on Tablet

mfstuart

Active Member
Licensed User
Longtime User
Hi all,
I'm building an android tablet app that lists song charts. Each chart is one of the following file types: .PDF, .DOC, or .DOCX.
All the files have been manually downloaded to the tablet from a DropBox, maintained by someone else.

The tablet download folder is under the Documents folder as: Charts\Gospel Jam
I'm able to list al the files into a ListView with no problem. This is done an a different page than the Main Page - ImportFiles.
The ImportFiles page has a button that reads the ListView (with the downloaded filenames) and adds the Filename to a SQLITE db.

From the Main Page, a ListView is populated from the SQLITE db. There the user can touch on a row and open the song chart to view for playing their instrument.

I'm having troubles with opening the selected file!
I've used this code to try and open the file, but have not been able to get it to work.
B4X:
Private Sub lvSongs_ItemClick(Position As Int, Value As Object)
    Dim lvd As lvData
    lvd.Initialize
    lvd = Value
    If Value <> "" Then
        Dim title As String = lvd.Ttl
        Log(title)
        Dim in As Intent
        in.Initialize(in.ACTION_VIEW,"")
        Dim tURI As String = Provider.GetFileUri(title)
        Log(tURI)
        Provider.SetFileUriAsIntentData(in,title)    'Provider has been defined in the Process_Globals
       
        'Provider.SharedFolder = tURI
        'in.SetComponent("android/com.android.internal.app.ResolverActivity")
        in.SetType("application/pdf")
        StartActivity(in)
    End If
End Sub

I need to open any one of the file types mentioned above and display it with the Intent object.
What am I missing in my code?

Regards,
Mark Stuart
 

mfstuart

Active Member
Licensed User
Longtime User
You should use ContentChooser.
My app knows the filename and possibly the folder location, from the importing of the filenames into the ListView.
The ContentChooser (cc.Show) assumes the app doesn't know the filename. In my case it does, like I mentioned.

Looking at the ContentChooserDemo app from the forum, it shows that the app does not know the filename, so it is not a fit - it seems - to my situation.
Running the Demo app only returns the somewhat filename.
I need it to open the file and display it.
If ContentChooser is a fit, I'm not seeing it.

Anyone care to clarify?

Thanx,
Mark Stuart
 
Upvote 0

Brian Dean

Well-Known Member
Licensed User
Longtime User
Your app may know the names and path of the files that it wishes to read, but unless they are in internal app memory, or unless your app is running at a downlevel sdk, then it will not be able to access those files without first obtaining permission from the user. This is a much discussed topic. There are some work-around options to be found in this forum but they depend on how you intend to deploy your app.
 
Upvote 0

mfstuart

Active Member
Licensed User
Longtime User
You should use ContentChooser.
I think you may have overlooked something in my comments and code above.

The user has already imported all the filenames needed for the app to work and therefore the app already has been given the permission to access the tablet folder to be used. Can't that folder and whatever object be used again? The value updated and kept in a Public variable?
I don't want the user have to use the ContentChooser everytime a song is selected. What would be the point of importing the filenames? The filenames are imported so a search can be made to find the wanted song chart.
It should just open the file selected in the ListView.
Can't FileProvider or ExternalStorage be used to just open the selected filename in the ListView?

This is a reply to what Erel gave me as ContnetChooser, but with no other comments about what to do with it. (Yeah, I've searched on it. Not a solution for my app)
This is also a reply to Brian Dean's comment. I'm looking for a solution.
Besides, why can other android apps do this and B4A doesn't have a solution?

Regards,
Mark Stuart
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
Dim tURI As String = Provider.GetFileUri(title)
I think that GetFileUri requires the full file path but you are passing only the file name.

Try:
B4X:
Dim FullFilePath As String
FullFilePath = File.Combine([Dir of your files here], title)
Dim tURI As String = Provider.GetFileUri(FullFilePath)

Also:
B4X:
Dim Ext As String
Ext = filePath.SubString(FullFilePath.LastIndexOf(".") + 1).ToLowerCase
Select Ext
    Case "pdf"
        in.SetType("application/pdf")
    Case "" 'add other file extensions here.
End Select
StartActivity(in)

EDIT: slightly modified.
 
Last edited:
Upvote 0

Brian Dean

Well-Known Member
Licensed User
Longtime User
The user has already imported all the filenames needed for the app to work
I see. The word "imported" could mean many things - you could have "imported" the filenames from a data base or an internal file. As you were having trouble reading them I thought that might have been what you had done.

Edit : Sorry - I have re-read your first post. I had overlooked this line . . .
I'm able to list al the files into a ListView with no problem.
 
Last edited:
Upvote 0

mfstuart

Active Member
Licensed User
Longtime User
I think that GetFileUri requires the full file path but you are passing only the file name.

Try:
B4X:
Dim FullFilePath As String
FullFilePath = File.Combine([Dir of your files here], title)
Dim tURI As String = Provider.GetFileUri(FullFilePath)

Also:
B4X:
Dim Ext As String
Ext = filePath.SubString(FullFilePath.LastIndexOf(".") + 1).ToLowerCase
Select Ext
    Case "pdf"
        in.SetType("application/pdf")
    Case "" 'add other file extensions here.
End Select
StartActivity(in)

EDIT: slightly modified.
So here's my current code for selecting and opening a file (pdf, doc, docx) from a ListView.
I set the code with your hints into my code...
B4X:
Private Sub lvSongs_ItemClick(Position As Int, Value As Object)
    IME.HideKeyboard
    
    Dim lvd As lvData      'Type defined in Globals     Type lvData(Ttl As String,Art As String,id As String)
    lvd.Initialize
    lvd = Value
    If Value <> "" Then
        Dim title As String = lvd.Ttl
        Dim FullFilePath As String
        Dim cfp As String = Starter.ContentFolderPath   'Set after the importing of the filenames from the selected folder. Done on another Activity.
        FullFilePath = File.Combine(cfp,title)
        Log(FullFilePath)       ' Produces:    content:/com.android.externalstorage.documents/tree/primary%3ACharts%2FGospel%20Jam/A Daisy A Day.pdf
        rp.GetAllSafeDirsExternal(cfp)    'thought this might help with setting the permission to External folders
        
        Dim in As Intent
        in.Initialize(in.ACTION_VIEW,FullFilePath)
        
        Dim ext As String = GetExt(title)
        Select ext
            Case "pdf"
                in.SetType("application/pdf")
            Case "doc"
                in.SetType("application/doc")
            Case "docx"
                in.SetType("application/docx")
        End Select
        
        in.SetComponent("android/com.android.internal.app.ResolverActivity")
        StartActivity(in)
    End If
End Sub

Sub GetExt(filename As String) As String
    Dim ext As String
    ext = filename.SubString(filename.LastIndexOf(".") + 1).ToLowerCase
    Return ext
End Sub

Running the app on the tablet in Debug Mode produces the following results:
From the ListView, touch the song to open.
The "Open With" system dialog opens to select which app to view the file. I had installed the file reader called "ReadEra".
I selected this app, since it can open and view multiple file types and has no ads or in-app purchases.

A screen/app appears with the following statement...

Unable to perform request
content:/com.android.externalstorage.documents/tree/primary:Charts/Gospel Jam/A Daisy A Day.pdf
I press the Back button and it returns to my app. It did not open the file and my app did not crash.

A post from @tsteward was able to open PDF files on this post HERE.
I'll reach out to him and see what he has.

Regards,
Mark Stuart
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
This works in my test:
B4X:
Private Sub Button1_Click
    Dim in As Intent
    in.Initialize(in.ACTION_VIEW,"")

    Dim filePath As String = File.Combine(FileDir, FileName)

    If File.Exists(FileDir, FileName) Then
        Dim tURI As String = provider.GetFileUri(filePath)
        Log(tURI)
        provider.SetFileUriAsIntentData(in, filePath)
       
        Dim FileType As String
        FileType = GetExt(filePath)
        Select FileType
            Case "pdf"
                in.SetType("application/pdf")
        End Select
        StartActivity(in)
    Else
        Log("File not found: " & filePath)
        ToastMessageShow("File not found", False)
    End If
End Sub

rp.GetAllSafeDirsExternal(cfp) 'thought this might help with setting the permission to External folders
No, that just returns the directories.
 
Upvote 0

mfstuart

Active Member
Licensed User
Longtime User
Your app may know the names and path of the files that it wishes to read, but unless they are in internal app memory, or unless your app is running at a downlevel sdk, then it will not be able to access those files without first obtaining permission from the user. This is a much discussed topic. There are some work-around options to be found in this forum but they depend on how you intend to deploy your app.
Hi Brian,
I created my folders on the Internal storage card as: Charts/Gospel Jam. I copied from DropBox all the files into this sub folder.
My code (see post #8) produces the following thou: content:/com.android.externalstorage.documents/tree/primary%3ACharts%2FGospel%20Jam/A House Of Gold in D.pdf
It references the externalstorage. Not sure why, instead of maybe internalstorage.
This works in my test:
B4X:
Private Sub Button1_Click
    Dim in As Intent
    in.Initialize(in.ACTION_VIEW,"")

    Dim filePath As String = File.Combine(FileDir, FileName)

    If File.Exists(FileDir, FileName) Then
        Dim tURI As String = provider.GetFileUri(filePath)
        Log(tURI)
        provider.SetFileUriAsIntentData(in, filePath)
      
        Dim FileType As String
        FileType = GetExt(filePath)
        Select FileType
            Case "pdf"
                in.SetType("application/pdf")
        End Select
        StartActivity(in)
    Else
        Log("File not found: " & filePath)
        ToastMessageShow("File not found", False)
    End If
End Sub


No, that just returns the directories.
Hi Lucas,
Care to show the value of your variables: FileDir and FileName
 
Upvote 0

mfstuart

Active Member
Licensed User
Longtime User
Set FileDir to the your files dir (where you downloaded them).

The FileName is the file name of your files.

(In my test, FileDir is File.DirInternal, FileName is My.pdf).
OK, thank you Luca.
I may have to move/copy the chart files to the DirInternal. It seems that is the difference with your app code working.
 
Last edited:
Upvote 0
Top