Android Question Problem with DirRootExternal and DirDefaultExternal

Cesaral

Member
I have done a simple program to test the creation and access to text files, but I am not able to make them work.

Find the test program attached.

I have upgraded B4A to the latest version and it still gives the same errors. The erros I get are:

Error occurred on line: 72 (Main)
java.io.FileNotFoundException: /storage/emulated/0/DirRootExternal.txt: open failed: EPERM (Operation not permitted)
at libcore.io.IoBridge.open(IoBridge.java:492)
at java.io.FileOutputStream.<init>(FileOutputStream.java:236)
at anywheresoftware.b4a.objects.streams.File.OpenOutput(File.java:449)
at java.lang.reflect.Method.invoke(Native Method)
at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:732)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:348)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:255)
at java.lang.reflect.Method.invoke(Native Method)
at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:144)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:197)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:193)
at anywheresoftware.b4a.objects.ViewWrapper$1.onClick(ViewWrapper.java:80)
at android.view.View.performClick(View.java:8160)
at android.widget.TextView.performClick(TextView.java:16222)
at android.view.View.performClickInternal(View.java:8137)
at android.view.View.access$3700(View.java:888)
at android.view.View$PerformClick.run(View.java:30236)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:246)
at android.app.ActivityThread.main(ActivityThread.java:8512)


Error occurred on line: 86 (Main)
java.io.FileNotFoundException: /storage/emulated/0/Android/data/b4a.example/files/DirDefaultExternal.txt: open failed: ENOENT (No such file or directory)
at libcore.io.IoBridge.open(IoBridge.java:492)
at java.io.FileOutputStream.<init>(FileOutputStream.java:236)
at anywheresoftware.b4a.objects.streams.File.OpenOutput(File.java:449)
at java.lang.reflect.Method.invoke(Native Method)
at anywheresoftware.b4a.shell.Shell.runMethod(Shell.java:732)
at anywheresoftware.b4a.shell.Shell.raiseEventImpl(Shell.java:348)
at anywheresoftware.b4a.shell.Shell.raiseEvent(Shell.java:255)
at java.lang.reflect.Method.invoke(Native Method)
at anywheresoftware.b4a.ShellBA.raiseEvent2(ShellBA.java:144)
at anywheresoftware.b4a.BA.raiseEvent2(BA.java:197)
at anywheresoftware.b4a.BA.raiseEvent(BA.java:193)
at anywheresoftware.b4a.objects.ViewWrapper$1.onClick(ViewWrapper.java:80)
at android.view.View.performClick(View.java:8160)
at android.widget.TextView.performClick(TextView.java:16222)
at android.view.View.performClickInternal(View.java:8137)
at android.view.View.access$3700(View.java:888)
at android.view.View$PerformClick.run(View.java:30236)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:246)
at android.app.ActivityThread.main(ActivityThread.java:8512)

I would appreciate ANY help that could solve this issue.

Thanks!
 

Cesaral

Member
Sorry it is GetSafeDirDefaultExternal. See the tutorial. It is explained.
In that thread I can only find this sentence, but no explanations or examples:

"It will not work with targetSdkVersion=30. Avoid using File.DirRootExternal. Either use File.DirInternal or RuntimePermissions.GetSafeDirDefaultExternal."

It would be so good to have this specific topic explained in detail....I really think it would save a lot of time to the members of this great community and to such an amazing programming tool the B4X is.

Thanks!
 
Upvote 0

KMatle

Expert
Licensed User
Longtime User
so that the App can fill in this log and the PC/MAC can easily access it

So it's more a design question. Your PC needs to access the logfile(s). You could establish a connection via WiFi (or Bluetooth) via AsyncStreams or any other method available.

Beneath that: You can share the logfile(s) from DirInternal, too (if needed). In my apps I never use external storage anymore (except you need to provide media files in the gallery or so).

Example (to share from internal). Change the type to application/text for textfiles (browse the www to get all types)

In Globals
SharedFolder=File.Combine(File.DirInternal, "shared"):
SharedFolder=File.Combine(File.DirInternal, "shared")

Manifest
B4X:
AddApplicationText(
  <provider
  android:name="android.support.v4.content.FileProvider"
  android:authorities="$PACKAGE$.provider"
  android:exported="false"
  android:grantUriPermissions="true">
  <meta-data
  android:name="android.support.FILE_PROVIDER_PATHS"
  android:resource="@xml/provider_paths"/>
  </provider>
)


CreateResource(xml, provider_paths,
   <files-path name="name" path="shared" />
)

Code to share:
B4X:
Dim i As Intent
    i.Initialize("android.intent.action.SEND_MULTIPLE", "")
    i.SetType("application/pdf")
 
    Dim Uris As List
    Uris.Initialize
 
    Dim Files As List=File.ListFiles(SharedFolder)
    For Each pdffile As String In Files
        Dim u As Uri = GetFileUri(pdffile)
        Uris.Add(u)
    Next
 
    Dim jo As JavaObject = i
    jo.RunMethod("putParcelableArrayListExtra", Array As Object("android.intent.extra.STREAM", Uris))
    i.Flags = 1
 
    StartActivity(i)
 
Upvote 0

Cesaral

Member
I
So it's more a design question. Your PC needs to access the logfile(s). You could establish a connection via WiFi (or Bluetooth) via AsyncStreams or any other method available.

Beneath that: You can share the logfile(s) from DirInternal, too (if needed). In my apps I never use external storage anymore (except you need to provide media files in the gallery or so).

Example (to share from internal). Change the type to application/text for textfiles (browse the www to get all types)

In Globals
SharedFolder=File.Combine(File.DirInternal, "shared")"shared"):
SharedFolder=File.Combine(File.DirInternal, "shared")

Manifest
B4X:
AddApplicationText(
  <provider
  android:name="android.support.v4.content.FileProvider"
  android:authorities="$PACKAGE$.provider"
  android:exported="false"
  android:grantUriPermissions="true">
  <meta-data
  android:name="android.support.FILE_PROVIDER_PATHS"
  android:resource="@xml/provider_paths"/>
  </provider>
)


CreateResource(xml, provider_paths,
   <files-path name="name" path="shared" />
)

Code to share:
B4X:
Dim i As Intent
    i.Initialize("android.intent.action.SEND_MULTIPLE", "")
    i.SetType("application/pdf")
 
    Dim Uris As List
    Uris.Initialize
 
    Dim Files As List=File.ListFiles(SharedFolder)
    For Each pdffile As String In Files
        Dim u As Uri = GetFileUri(pdffile)
        Uris.Add(u)
    Next
 
    Dim jo As JavaObject = i
    jo.RunMethod("putParcelableArrayListExtra", Array As Object("android.intent.extra.STREAM", Uris))
    i.Flags = 1
 
    StartActivity(i)
Thanks for your answer. I don´t like using for a LOG file File.DirInternal because if you uninstall app, you will lose the LOG. This is why in my opinion for a LOG file the best is to save it in a folder that can be read once the Android device is connected to a PC/MAC thru a cable (to speed up the download process).

Thanks anyway for sharing this interesting code!
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
Using Dir.DefaultExternal or rp.GetSafeDirDefaultExternal will not help. These folders are deleted when the app is uninstalled.
Are not kept files in the DirInternal unless you set:
Disable Android backup feature with this line (manifest editor):
B4X:
SetApplicationAttribute(android:allowBackup, "false")
?
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
If you want your files to be accessible when the device is connected as a USB mass storage device then you can use rp.GetSafeDefaultExternal.
For a long time I have had a damn problem with both the USB driver and the particular smartphone model (Huawei), so I can't connect the device via USB.

Using rp.GetSafeDirDefaultExternal I was able to copy on the laptop the "private" db of the app I am developing, using ftp - Filezilla and the B4A Bridge (maybe I could also use DirRootExternal since I have Android 8 but I don't want to investigate).

I think I'll write a snippet or maybe a tutorial about this, that is the app writes the db in the DirInternal, so it is "protected", or in the rp.GetSafeDirDefaultExternal depending on the conditional symbol. This will make it easier to verify what the app has changed in the db, without having to write queries to check.

It would be even better if Erel wrote it, who could explain it better ;)
 
Upvote 0

LucaMs

Expert
Licensed User
Longtime User
For a long time I have had a damn problem with both the USB driver and the particular smartphone model (Huawei), so I can't connect the device via USB.

Using rp.GetSafeDirDefaultExternal I was able to copy on the laptop the "private" db of the app I am developing, using ftp - Filezilla and the B4A Bridge (maybe I could also use DirRootExternal since I have Android 8 but I don't want to investigate).

I think I'll write a snippet or maybe a tutorial about this, that is the app writes the db in the DirInternal, so it is "protected", or in the rp.GetSafeDirDefaultExternal depending on the conditional symbol. This will make it easier to verify what the app has changed in the db, without having to write queries to check.

It would be even better if Erel wrote it, who could explain it better ;)
https://www.b4x.com/android/forum/threads/my-way-to-work-with-local-db.139215/
 
Upvote 0
Top