Android Question Problem accessing external SD Card

William Hunter

Active Member
Licensed User
Longtime User
I have been trying to transfer files via Bluetooth between two Samsung devices. The problem I am having is trying to write those transferred files to an external SD Card. I can’t do this. The files are always written to internal on device storage. The External SD Card does not seem to be seen as writable.

The first device runs Android 4.1.2, and shows storage as sdcard0 and extSdCard.

The second device runs Android 4.0.4, and shows storage as sdcard and extSdCard.

I am using the code below, which to me appears to be correct in all respects. Am I missing something, or have Android’s volume mounting points become problematic for accessing?

B4X:
If File.ExternalWritable Then
    If File.IsDirectory(File.DirRootExternal, "FileTransferBT") = False Then
        File.MakeDir(File.DirRootExternal, "FileTransferBT")
    End If
    astream.StreamFolder = File.DirRootExternal & "/FileTransferBT"
Else
    If File.IsDirectory(File.DirDefaultExternal, "FileTransferBT") = False Then
        File.MakeDir(File.DirDefaultExternal, "FileTransferBT")
    End If
    astream.StreamFolder = File.DirDefaultExternal & "/FileTransferBT"
End If

Below is the Manifest.

B4X:
'This code will be applied to the manifest file during compilation.
'You do not need to modify it in most cases.
'See this link for for more information: http://www.b4x.com/forum/showthread.php?p=78136
AddManifestText(
<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="14"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<supports-screens android:largeScreens="true" 
    android:normalScreens="true" 
    android:smallScreens="true" 
    android:anyDensity="true"/>)
SetApplicationAttribute(android:icon, "@drawable/icon")
SetApplicationAttribute(android:label, "$LABEL$")
'End of default text.

Any help or enlightenment would be greatly appreciated. :confused:
 
Last edited:

Douglas Farias

Expert
Licensed User
Longtime User
Try this

B4X:
Dim astream.StreamFolder as string

B4X:
If File.ExternalWritable Then
    If File.IsDirectory(File.DirRootExternal, "FileTransferBT") = False Then
       File.MakeDir(File.DirRootExternal, "FileTransferBT")
    End If
    astream.StreamFolder = File.Combine(File.DirRootExternal,"FileTransferBT")
Else
    If File.IsDirectory(File.DirDefaultExternal, "FileTransferBT") = False Then
        File.MakeDir(File.DirDefaultExternal, "FileTransferBT")
    End If
    astream.StreamFolder = File.Combine(File.DirDefaultExternal,"FileTransferBT")
End If

and try to add too in manifest

B4X:
android.permission.WRITE_MEDIA_STORAGE
 
Last edited:
Upvote 0

William Hunter

Active Member
Licensed User
Longtime User
Try this

B4X:
android.permission.WRITE_MEDIA_STORAGE

Thank you for the reply Douglas.

I added the “android.permission.WRITE_MEDIA_STORAGE” permission to the Manifest. This did not make any difference. I still cannot transfer a file to the external CD Card.

I have been doing a little reading on the Internet, and apparently this is by design in later versions of Android. In the past, an app would request the "WRITE_EXTERNAL_STORAGE" permission, which would grant write access to all external storage areas. This has apparently been changed to only grant write access to the primary external storage. A second permission has been introduced called "WRITE_MEDIA_STORAGE", which would grant access to other external storage areas. The problem is, a third party will not actually be granted this permission. Only system apps and apps provided by the device manufacturer will normally be granted this permission.

This is my understanding of the situation, and I’m annoyed that access to an External SD card is limited in this way. It makes the SD Card virtually useless. :(
 
Upvote 0

Douglas Farias

Expert
Licensed User
Longtime User
but you have try my code? with combine and witout "/" ?
i think the problem is the /
 
Upvote 0

William Hunter

Active Member
Licensed User
Longtime User
but you have try my code? with combine and witout "/" ?
i think the problem is the /

Thank you again Douglas. The code with the / works well in transferring files to on board device storage (sdcard or sdcard0). The / is required as a separator in the path to the directory just created (FileTransferBT). The problem I have is in writing to an external SD Card, otherwise the transferring of files to on board storage works well with the / in place.
 
Last edited:
Upvote 0

William Hunter

Active Member
Licensed User
Longtime User
I have been down this road before, with an app I was writing over a year ago. How soon we forget. In earlier versions of Android there was no way to write directly to the root of on-board storage. We only had File.DirInternal or File.DirInternalCache which are private to our application. In order to have data accessible to third party apps, other than our own, we had the option of saving data to a writeable external SD Card. Now in later versions of Android, we have lost the ability to write to an external SD Card.

There are now a number of older to newer versions of Android running on devices currently in use. Considering that we are dealing with Froyo to KitKat, It seems to me to be impossible to write an app to transfer files wirelessly between devices and have those files accessible to a third party app on the receiving device, for all of these various versions of Android.

With newer versions of Android, now having the ability to write to the root of on-board storage, this isn’t too much of a problem. But with an earlier version such as Froyo, if there is not an external SD Card to write the file to, it can only be written to File.DirInternal or File.DirInternalCache. This makes the file inaccessible to other third party apps, which makes the ability to transfer files between devices a redundant exercise for these earlier versions of Android.

I may be mistaken in this, but I can’t find a way to reliably write to the root of on-board storage across all versions of Android, Froyo to KitKat. If there is a way of doing this I would appreciate some guidance.

Best regards :)
 
Upvote 0

William Hunter

Active Member
Licensed User
Longtime User
I have another app that is based on Erel’s HTTP Server example, with only a few cosmetic changes and the added ability to delete files from the Android device. Other than that it’s the same code that’s in Erel’s tutorial example.

This app uses code to obtain the path to the SD Card, and any content. I have no problem transferring files to the SD Card with this app. The difference between the two apps, with one using a coded path statement while the other uses File.DirRootExternal for the path, seems to be key here.

I am not an Android expert, but it seems to me that this is not a permissions problem, but rather the inability to point to the external SD Card using File.DirRootExternal. Otherwise, why would Erel’s HTTP Server example be able to write to the External SD Card using a coded path, while his Bluetooth example using (File.DirRootExternal) will fail?

I wish Google would fix Android so that it was an easy chore to determine the paths of all the possible storage mount points, and also provide the means of writing to external storage as well as on-board storage. I’m finding that there are sticky points with Android that make me think Google is just being plain nasty. There’s no good reason for this nonsense. Google needs to get its ass in gear to resolve this issue, and also to resolve the issue preventing users from blocking unnecessary permissions. But I guess when you’re all ass that’s hard to do. :eek:

I've vented. Best regards to all.
 
Upvote 0

William Hunter

Active Member
Licensed User
Longtime User
Can you post the error message from the logs?

Hello Erel – My comment “while his Bluetooth example using (File.DirRootExternal) will fail” has been misinterpreted. I did not mean that the file transfer failed, but that my personal objective of transferring the file to the SD Card failed. The file was transferred to on-board secondary storage, which (File.DirRootExternal) now points to on later versions of Android. I believe that to be with Jelly Bean and up. With earlier versions of Android it pointed to an external SD Card. (I know File.DirDefaultExternal points to the default folder for an application on the SD card. I had just been using this in experimenting with an earlier version of Android. It’s not significant to the issue.)

B4A is working just fine, and doing everything it’s supposed to do. I have not logged any errors to report. My beef is with Google. I can’t fathom their actions in preventing write access to an external SD Card. If they feel it to be for reasons of security I would like to hear their theory. If they see it as a part of a DRM strategy to protect downloaded content, what does it matter where the content is stored if it’s not stored in a private area? I just don’t get it, with this and other of their actions of late.

My personal view is that full read/write access to an SD card should not be restricted in any way. Preventing write access to the SD Card restricts the fair use of any device equipped with an external SD Card. I would call it, at the very least, misleading if not false advertising.

Now, for the kicker! Having trashed the evil empire for preventing my writes to the External SD Card, why am I able to write to the storage area of my choosing, whether that be sdcard, sdcard0 or ExtSdcard, using your HTTP Server example? (sdcard, and sdcard0 are on-board storage locations on two different Samsung devices, while ExtSdcard is an External SD Card on each of these devices.) Talk about a confusing issue. Like I said, I don’t get it.

Your example is here:
http://www.b4x.com/android/forum/th...n-your-android-application.25984/#post-150463

Thank you for your interest, and best regards. :)
 
Last edited:
Upvote 0

William Hunter

Active Member
Licensed User
Longtime User
I’m like a dog chewing on a bone, but seem to have made a little headway for my own purposes. I have come up with a means of writing to the External SD Card, although it would not be helpful to those wishing to distribute their apps.

I have added the android.permission.READ_EXTERNAL_STORAGE permission to the manifest as below:
B4X:
'This code will be applied to the manifest file during compilation.
'You do not need to modify it in most cases.
'See this link for for more information: http://www.b4x.com/forum/showthread.php?p=78136
AddManifestText(
<uses-sdk android:minSdkVersion="4" android:targetSdkVersion="14"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<supports-screens android:largeScreens="true"
    android:normalScreens="true"
    android:smallScreens="true"
    android:anyDensity="true"/>)
SetApplicationAttribute(android:icon, "@drawable/icon")
SetApplicationAttribute(android:label, "$LABEL$")
'End of default text.

The code below writes to the internal on-board storage location only. This is the problem.
B4X:
Private Sub StartAStream (In As InputStream, out As OutputStream)
    Log("StartAStream")
    astream.InitializePrefix(In, True, out, "astream")
    If File.ExternalWritable Then
        If File.IsDirectory(File.DirRootExternal, "FileTransferBT") = False Then
              File.MakeDir(File.DirRootExternal, "FileTransferBT")
        End If
          astream.StreamFolder = File.DirRootExternal & "/FileTransferBT"
      Else
        Msgbox("Storage space not available ...","Unable to transfer")
    End If
End Sub

The code below writes to the External SD Card, when one is present. This is my solution.
B4X:
Private Sub StartAStream (In As InputStream, out As OutputStream)
    Log("StartAStream")
    astream.InitializePrefix(In, True, out, "astream")
    If File.IsDirectory("/mnt/extSdCard", "") = True Then ' SD Card on Galaxy Note 10.1 & Galaxy Phone
        If File.IsDirectory("/mnt/extSdCard", "FileTransferBT") = False Then
            File.MakeDir("/mnt/extSdCard", "FileTransferBT")
        End If
        astream.StreamFolder = "/mnt/extSdCard/FileTransferBT"
    Else If File.IsDirectory("/mnt/sdcard0", "") = True Then ' On-board storage Galaxy Note 10.1
        If File.IsDirectory("/mnt/sdcard0", "FileTransferBT") = False Then
            File.MakeDir("/mnt/sdcard0", "FileTransferBT")
        End If
        astream.StreamFolder = "/mnt/sdcard0/FileTransferBT"
    Else If File.IsDirectory("/mnt/sdcard", "") = True Then ' On-board storage Galaxy Phone
        If File.IsDirectory("/mnt/sdcard", "FileTransferBT") = False Then
            File.MakeDir("/mnt/sdcard", "FileTransferBT")
        End If
        astream.StreamFolder = "/mnt/sdcard/FileTransferBT"
    Else
        Msgbox("Storage space not available ...", "Unable to transfer")
    End If
End Sub

This may be helpful to those developing apps for use on their own devices. There is a lot of chatter on the Internet re the removal of write privileges to the External SD Card. Some say it applies to Jelly Bean and up, while others say it starts with Kit Kat. I am running Jelly Bean on my two test devices, so I can’t say it will work with any Android version beyond that.

Best regards
 
Upvote 0

Douglas Farias

Expert
Licensed User
Longtime User
the best way is dont use sd card xD but your app is based on thiS :)
 
Upvote 0

William Hunter

Active Member
Licensed User
Longtime User
the best way is don't use sd card xD :)
Hi Douglas – I’m just an ornery S.O.B. that refuses to accept that I, the guy spending the bucks for this fairly expensive piece of hardware, shall have no write access to its SD Card. It has taken me two tablets and one smart phone to come to believe that the Android OS has deteriorated into a useless piece of crap.

It once held so much promise. But, I believe it’s time I looked at another platform for tablets and smart phones. I have no use for Apple devices, but I think I will look at some of the new touch enabled devices running Windows 8.1, and also Windows Phone. If they give unfettered access to SD Cards and USB drives, including the installation of third party apps to SD Cards they will have my first vote. If they allow some control of permissions, primarily the auto start of apps, they will have my second vote. I am very ticked off at Google’s throttling of Android. They are turning Android into an irrelevant OS, and that’s hard to fathom.

I hope Erel gives a priority to developing B4J, for I doubt there is another Android device in my future. In my part of the world sales of Android tablets have dropped off planet, and they wonder why. :eek:

Best Regards
 
Last edited:
Upvote 0

William Hunter

Active Member
Licensed User
Longtime User
File.DirRootExternal doesn't point to an external sd card. It points to the secondary storage which on almost all devices is not the sd card.

Hello Erel - I have two final questions re File.DirRootExternal. Is there now uniformity across all versions of Android, from Froyo to Kit Kat, in that it will always point to on-board secondary storage? Will read/write access to an External SD Card become totally blocked to third party apps in future versions Android?

Cheers :)
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
I have two final questions re File.DirRootExternal. Is there now uniformity across all versions of Android, from Froyo to Kit Kat, in that it will always point to on-board secondary storage?
I didn't saw any device who didn't have an "internal" secondary storage (File.DirRootExternal). Practically you need to check File.ExternalWritable. If it is false then use the File.DirInternal instead.

Starting from Android 4.4 your app can only access one specific folder in the sd card (based on the package name).
 
Upvote 0

William Hunter

Active Member
Licensed User
Longtime User
Practically you need to check File.ExternalWritable. If it is false then use the File.DirInternal instead.

Starting from Android 4.4 your app can only access one specific folder in the sd card (based on the package name).

Thank you Erel – This would all make sense to me, if only there were a means of checking for an External SD Card, such as “If File.DefaultExternalWritable = True Then”. The fact that File.ExternalWritable checks for "internal" secondary storage seems a misnomer to me. Even if R/W access to an External SD Card is to become private to third party apps, one would think a means of validating that an External SD Card actually existed would be necessary. My mind must not be Googled in the right way. Although, I think they're pushing me in that direction. If they keep this up, I should soon be right Googley.

Best Regards :)
 
Upvote 0

izzet kalinsazlioglu

New Member
Licensed User
Longtime User
i try lot of methot but

when i use
"/mnt/external_sd"
instead of
File.DirRootExternal

it works.



File.WriteString("/mnt/external_sd" , "String4.txt", _
"2222 is some string" & CRLF & "and this is another one.")
 
Upvote 0
Top