I have an Android app (developed under Xamarin.Android) which works fine when I test it locally on both emulators and physical devices. However, it fails on two physical devices (Moto G4, API 23, and Huawei Mate 9, API 24) when it goes through automatic testing on the Google Play Console. The problem arises when trying to create a log file in external storage. I have been running various tests under Firebase on the Moto G4, but cannot work out where the problem lies. I would be really grateful for at least one more pair of eyes on what I’m doing.
I check Android.OS.Environment.ExternalStorageState, which returns “MediaMounted”. I then use GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryDownloads) to work out where to create my log file. This returns “/storage/emulated/0/Download”. I next check that read/write permission has been granted. ContextCompat.CheckSelfPermission(this, Android.Manifest.Permission.ReadExternalStorage) and ContextCompat.CheckSelfPermission(this, Android.Manifest.Permission.WriteExternalStorage) both return Android.Content.PM.Permission.Granted. (In AndroidManifest.xml, I list <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />.)
At this point, I have established (I think) that the directory exists and that I have permission to write to it, so I try to create my log file, /storage/emulated/0/Download/LogFile.txt. This works fine locally, on both emulators and physical devices. It also works on most of the devices that the Google Console test puts to test. However, on the Moto G4 (physical device), file creation fails with the error “Could not find part of the path”.
I have also tried writing to DirectoryDocuments instead of DirectoryDownloads, which the Android documentation tells me is the “standard directory in which to place documents that have been created by the user”. The path returned for this is /storage/emulated/0/documents. When I try to write to that directory, it fails saying that the directory does not exist (which I believe is true).
Enumerating the contents of the Download directory, I noticed that there is a “Documents” directory inside the Download directory, i.e. /storage/emulated/0/Download/Documents. Writing to this directory again gives me the error “could not find part of the path”, same as writing to the Download directory itself.
My app absolutely has to store files somewhere (not just the log file). It is also important that the user can copy these files to/from the device, and I don’t want the files to be deleted, even if the app is uninstalled. For these reasons, I believe that external storage is the right (only) place for them.
I am at a loss to know what to try next. (I am wondering now whether there is actually an issue with the device, like a disk format issue.) If anyone has any suggestions on where to go from here, I would be really grateful! Extensive searches have not thrown up anything that I'm doing wrong, or any suggestion that the directory structure may be different on a Moto G4.
Related
I recently bought a Samsung Galaxy S20 FE with Android 12, and I quickly noticed that many applications were unable to access files on the SD card. For instance, I used to access local HTML/MP3 files from different browsers or music players. On my new system, these applications can see folders and navigate through them, but can not open or even list any regular file. There is a few exceptions, e.g Total Commander or AIMP.
From what I understood, this is a policy change from Google which appeared on Android 11 (API/SDK 30): https://www.xda-developers.com/android-11-all-files-access-permission-form/
I tried a few solutions I could find online, for instance:
pm grant com.XXX.YYY android.permission.MANAGE_EXTERNAL_STORAGE
appops set --uid com.XXX.YYY android:legacy_storage allow
This is not working because, probably, the application (i tried with Opera) is not requesting this permission during the installation. Also, most of the solutions I could find are related to apps under development, not apps installed from the store. E.g. : Android 11 Scoped storage permissions
A workaround I could find is to move all the files in /storage/SD_CARD_ID/Android/data/com.XXX.YYY/files, however, this means that I have to copy these files each time I install a new app and for each app I use, which is quite stupid if I have GB's of MP3 or other media. This is also quite tedious to enter the full path in the URL bar as it is not possible to navigate to or open this folder easily.
I am therefore trying to find a way to enable the permission by default for all apps, or at least find a simple way to do it via the GUI. For instance, I tried to tweak /etc/permissions/platforms.xml with some more or less random tries as I could not find any documentation about the syntax of this file, but nothing worked.
Note that my phone is rooted.
I'm developing application that is targeted for API 18. Application download data by Bluetooth and GSM and stores data on internal sdcard (usually \emulated\sdcard - readed by Environment.getExternalStorageDirectory()).
Till this time everything works fine - files and folders are correctly saved.
Today i've faced very strange behaviour:
1) Started the app, and it works for over an hour and store data files.
2) After that, i've closed app and want to download data to the computer.
Before plugin USB, I've used Android file explorer software to check stored data.
I was shocked - new folder (any new data) was gone!
It's like system removes or hide all files and data created in last app session.
Remarks: application don't have procedures for deletion folder or files. Also it works good on previous versions of Android (mostly 4.X and 5.X).
It's very strange because app has warning mechanism when save isn't possible and that warnings wasn't displayed. So I think, write was allowed by system, but data isn't visible at this moment.
Another stranger thing is that application can't write any file in internal storage from this moment (and the warnings are displayed as should in this case).
It looks like Android Marshmallow "decides" in particular moment - your new data won't be available anymore, and your app won't write to internal card.
I've checked app permissions in system - OK.
Any ideas, why this happens? How to deal with it?
You may refer to these guides for managing permissions during runtime: http://www.howtogeek.com/230683/how-to-manage-app-permissions-on-android-6.0/
https://developer.android.com/training/permissions/requesting.html
I am working on a project that needs to store some .txt to android, and get it from the computer for other use. From what I read from the documentation, I know that there are two types of storage: 1 Internal, which is somewhere deep in the phone that is private to the app. 2 External, which includes the SD card and the Internal Storage of the phone. I want to store it to External->Internal, and I am using this line of code to do that:
public String WalkDir = android.os.Environment.getExternalStorageDirectory().getAbsolutePath() + "/Walks/";
When I logged WalkDir, LogCat says "/storage/emulated/0", I stopped the app, checked with the adb shell, and there is no folder "0" but "legacy". I unplugged the phone and plugged it back in, the "Walks" folder is now in the root directory, and I don't need adb shell to access it.
So my question is, can you help explain how this system works? Why did "0" disappear? What is "legacy"? Why is the file in Internal Storage when I unplug&plug it?
Thank you very much!
Those are what in Linux are called symlinks (like shortcuts in Windows) that various system apps in Android are using..
/storage, /sdcard are sym linked folders,that means when you open one of those, it redirects to the original(/data/media/0), as for the 0 is just a multi user feature implemented in android 4.2, but only enabled on tablet androids.
Why do this Sym-Link?: simple so it dosent break apps(not only file explorer type of app, but all apps).
Still dont get, why it would break?.Simple. android api have lots of ways to write/read files from folders, u can do manually,u can get the data path, u can get the sdcard path, etc,etc. so to not break that they just does these sym links, thats why in one app the storage contentents are listed on /sdcard but on others, is /storage, etc,etc. one example of an app that broke because of these changes to android is titanium backup, u need to change the internal storage on it, so it work.
2 mount points pointing to the same storage device and partition.
If you create something in one folder, it will show up in the other. Same applies for deleting stuff.
They do not take away more storage space, as it is only available once but shown twice.
You also don't need to worry about it in any way because file browsers normally set their default directory to one of these locations.
As far as i know, Google changed the mount points in Android 4.2 to /storage/emulated/0/ due to them switching to MTP and EXT4(?) for the sdcard. The other mount points are still there for compatibility.
On Android 4.4.2 Environment.getExternalStorageDirectory().getPath() returns /storage/emulated/0 but this path does not exist on my Nexus5 Android 4.4.2. Environment.getExternalStorageDirectory().getPath() worked up until Android 4.4.2.
How can I get the /sdcard path on Android 4.4.2?
This path does not exist on my Nexus5 Android 4.4.2.
Yes, it does, for your process at runtime.
For example, this sample project downloads a file to Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS). If you log the location at runtime, when running it on a Nexus 5, it is reported as /storage/emulated/0/Download. And the download succeeds.
If you are looking for /storage/emulated/0 via DDMS or adb shell, you will not find it. For those tools, default external storage is /mnt/shell/emulated/0. Hence, the downloaded file from the above sample appears in the /mnt/shell/emulated/0/Download directory.
AFAIK, the difference is tied to providing separate external storage to secondary accounts.
The Storage Options documentation says to use Environment.getExternalStorageDirectory() (as you are already correctly using). This function is available on all versions of Android.
Are you seeing it return a path that isn't actually available on a 4.2 device?
Please note (from Environment.getExternalStorageDirectory()):
Applications should not directly use this top-level directory, in order to avoid polluting the user's root namespace. Any files that are private to the application should be placed in a directory returned by Context.getExternalFilesDir, which the system will take care of deleting if the application is uninstalled. Other shared files should be placed in one of the directories returned by getExternalStoragePublicDirectory(String).
Writing to this path requires the WRITE_EXTERNAL_STORAGE permission, and starting in read access requires the READ_EXTERNAL_STORAGE permission, which is automatically granted if you hold the write permission.
Starting in KITKAT, if your application only needs to store internal data, consider using getExternalFilesDir(String) or getExternalCacheDir(), which require no permissions to read or write.
Sometimes /storage/emulated/0 can be written to, but reads fail... so tests for "writability" are not sufficient. This is such an annoying problem, I have come up with an equally annoying but effective solution.
Hardcode "/mnt/sdcard" Yea, I said it.
Looks like someone else said it first ... storing android application data on SD Card
More joy... http://forums.bignerdranch.com/viewtopic.php?f=414&t=7407
I've got a pretty thorny problem with Android 2.3: I have an app that gathers various logs for debugging and support purposes (my company does Linux for rugged hardware), and has stopped working lately, because it's failing to write to the SD card. Here are the symptoms I've seen and the investigations I've carried out:
Happens across multiple devices of multiple types with different SD cards, all of which have been checked for filesystem corruption (no issues found).
All devices report: Environment.getExternalStorageState() equals Environment.MEDIA_MOUNTED.
All devices also report that Environment.getExternalStorageDirectory().getAbsolutePath().canWrite() is false.
Via PackageManager.checkPermission(), my app reports that it has the WRITE_EXTERNAL_STORAGE permission.
OI File Manager is able to create directories and move files on the SD card; my app can do neither.
This code is sufficient to cause a failure:
String sdcardDirectory = Environment.getExternalStorageDirectory().getAbsolutePath();
File directory = new File(sdcardDirectory + "/logger");
if(!directory.mkdirs()){
//fails here.
Log.w("Logger", "Could not create logger directory.");
}
Since I have access to the keys for this device, I even went so far as to sign the app with the platform key and run it as android.uid.system, with no luck. Anyone have any ideas?
It turns out this is a case partly of bad diagnosis on my part, and partly an apparent change in 2.1 to 2.3.
The bad diagnosis was that the directory above was indeed being created. The apparent change between 2.1 and 2.3 may be Android internally, or it may be the way we're setting up paths, PATH, and symbolic links in our own builds. Further down from the code in the original post, there are a few calls to exec() to get e.g. output from logcat and copies of various bits of useful information in /proc; using absolute paths to the commands fixed the problem.
Thanks for the help in ruling things out.