Is getExternalFilesDir() private? - java

I'm trying to store music files users can download with my application, but I don't want them to be publicly visible to 99% of users (I'm excluding rooted devices or special cases)
I'm not worried about the people that go above and beyond to get the audio out by using special tools or a rooted phone.
I am trying to understand the docs but it's not 100% clear to me that getExternalFilesDir() is good to use for that purpose.
Also, the library I'm currently using uses the following line:
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath()
Is this 100% interchangeable if I just replace it with...
Environment.getExternalFilesDir(Environment.DIRECTORY_MUSIC).getAbsolutePath()
(notice I changed both the directory function, as well as the DIRECTORY type (from PICTURES to MUSIC)
Thanks

Is getExternalFilesDir() private?
No. Any user and any app (with READ_EXTERNAL_STORAGE or WRITE_EXTERNAL_STORAGE) can access external storage.
Is this 100% interchangeable if I just replace it with..
That won't compile due to imbalanced parentheses. Also, the values are different (PICTURES versus MUSIC). Ignoring that, it is "interchangeable" insofar as they will both work and will both be on external storage. However, they are not the same thing. The first one is the user's standard PICTURES directory; the second one is a directory dedicated for pictures that is unique to your app. Also, the former requires WRITE_EXTERNAL_STORAGE on all devices; the latter requires it only for Android 4.3 and below.
I don't want them to be publicly visible to 99% of users (I'm excluding rooted devices or special cases)
Use internal storage (e.g., getFilesDir()).

Use getFilesDir() instead. Thats private app memory.

if you put "." before folder name this folder be hidden
e.g:
String root = Environment.getExternalStorageDirectory().toString();
File myDir = new File(root + "/.myFolderName");

Related

getFilesDir() vs getExternalFilesDir(), which one is more recommended?

As far as I've noticed, using getFilesDir() to store data (camera captures in my case) is somewhat temporary. I say somewhat because if I close and reopen the app, I'm able to access the directory and files list, but not the file itself.
Is my logic wrong or is that by design?
Out of the 2 methods, which is more recommended in :
general
my case (privacy is needed)
Simply,
getFilesDir() refers to internal storage that cannot be accessible outside your application. It's not explorable by the device as well.
getExternalFilesDir() refers to external storage, it's a type of App-specific storage. this can be explorable as you find its directory in
data/data/your package name
In general, you may use external storage as internal storage may be limited.
For privacy, if you need you to file security, use getFilesDir() as it's not accessible outside your application as I mentioned before.
The main difference between the two is:
getFilesDir() - This path will be hidden from the user. This is more secure approach.
getExternalFilesDir() - Accessible by the user.
Received a good documentation on this which provides clear understanding:
http://androidvogella.blogspot.com/2015/12/getfilesdir-vs-getexternalfilesdir-vs.html
Update for the latest Android (currently Android 13)
In the old days getFilesDir() used to mean internal storage, and getExternalFilesDir() used to mean anything plugged in (usually an SD card).
These days phones don't have SD card slots, so the device emulates external storage by grabbing a slice of internal storage for the purpose. So the historic differences - that internal was faster and smaller, and external slower and larger - are generally no longer true.
In both cases apps get scoped storage - i.e. a directory they can access without permissions, which isn't accessible by any other app (though see below). This has been the case since Android 10 (but only enforced in Android 11).
Files stored under getFilesDir() and getExternalFilesDir() will be deleted when the app is uninstalled, but will persist until then. (If you're finding a file disappears before then, you have a different problem. I would suggest posting your code in a separate question).
The only major remaining difference between internal and external is that apps can get request a permission to read/write the entirety of external storage, including files it doesn't own. So don't use external for files that need to remain private to the app.
More information in this article: https://medium.com/#tdcolvin/demystifying-internal-vs-external-storage-in-modern-android-c9c31cb8eeec

java.lang.IllegalStateException: Not one of standard directories [duplicate]

Android Api 29 has big changes regarding files and folders.
I have not found a way so far to create a folder in the internal storage that is public visible.
Every folder I create can be seen by my app only.
I write an app that creates data files that shall be picked up by other apps, for instance the Total Commander to copy them to a destination.
Everything worked fine until I activated Api 29. Some of my clients DO use pixel phones and they use Android 10.
How can I create a folder and files in Android 10 that are public?
This has been deprecated:
Environment.getExternalStorageDirectory();
Environment.getExternalStoragePublicDirectory(type);
and when I use
File root = context.getExternalFilesDir(null);
The created files can only be seen by my app.
How can I achieve the behavior that was valid before Android 10?
Thanks in advance.
when I use File root = context.getExternalFilesDir(null); The created files can only be seen by my app
They can be seen by any app that uses the Storage Access Framework (e.g., ACTION_OPEN_DOCUMENT), if the user chooses the document that you place in that directory.
I write an app that creates data files that shall be picked up by other apps
Other apps have no access to external or removable storage on Android 10, except in the limited directories like getExternalFilesDir() or via non-filesystem means (ACTION_OPEN_DOCUMENT, MediaStore).
How can I create a folder and files in Android 10 that are public?
Use getExternalFilesDir() and related methods on Context. Or, use ACTION_CREATE_DOCUMENT or ACTION_OPEN_DOCUMENT_TREE and use the Storage Access Framework. In either case, the resulting documents can be used by other apps that also use the Storage Access Framework.
Starting from Android 10, you should use SAF, and let user choose the directory using ACTION_OPEN_DOCUMENT_TREE.
If you need a simple example. You can find it here
Alternatively, you could use requestLegacyExternalStorage = true in manifest when your app is not newly released. But, this is something that should not be used for future release, as this is a short-term solution provided by Google.
Note: In future releases of Android, user will not be able to pick the whole external file directory and Downloads directory, so unfortunately, keep in mind that we are not going to have access to these as well! For more information you can click here

how to grant full Write/Read files access on specifics folder in android Q

I noticed that my program on Android Q can not create any folder or save and open a file.
I've read Google's documentation but I did not find the answer or at least I did not understand Because there is a very small sample code, and as I figured out, every time you create a file, you need to open a special window
Someone can tell me how can I get a full access for special folder in sdcard?
I do not want to open a different window every time and confirm it
Long term, you have no means of forcing the user to give you access to a test/ directory on external storage.
You have three main options.
You can use getExternalFilesDir(), getExternalCacheDir(), or getExternalMediaDir(). These are methods on Context, and they each return a File pointing to a directory on external storage for which you have full read-write filesystem access. From the user's standpoint, these will be under Android/data/.../, where ... is your application ID.
Or, you can use ACTION_OPEN_DOCUMENT_TREE and the Storage Access Framework. Using startActivityForResult() with an ACTION_OPEN_DOCUMENT_TREE Intent will give you a Uri that points to a document tree, which may be on external storage, removable storage, or in the cloud. You can call takePersistableUriPermission() on a ContentResolver to get long-term access to that tree, and you can use DocumentFile.fromTreeUri() to work with that tree. However, this is not filesystem access — it is a bit closer to working with a Web server.
Or, you can add android:requestLegacyExternalStorage="true" to your <application> element in the manifest. This will give you legacy filesystem behavior on Android Q devices. This is scheduled to be removed for Android R, so this is not a suitable long-term solution.
I blogged about the Android Q storage changes a lot this year; here is my last(?) post on it.

Difference between getExternalFilesDir and getExternalStorageDirectory()

I understand that ExternalFiles is to be used on API 8 and up and getExternalStorageDirectory is for 7 and down. However I am a little confused between the use. For example I wanted to check that a folder that exists and previously you would use something like:
File ChildFolder = new File(Environment.getExternalStorageDirectory() + "/ParentFolder/Child");
However every example I see says to use getExternalFilesDir (null), File.ext. Since I am above API 8 I want to use this method but how do I just check for a folder? I will check for a files existence at another point but for now just want to see if the folders exist??
getExternalFilesDir()
It returns the path to files folder inside Android/data/data/your_package/ on your SD card. It is used to store any required files for your app (e.g. images downloaded from web or cache files). Once the app is uninstalled, any data stored in this folder is gone too.
getExternalStorageDirectory()
It returns the root path to your SD card (e.g mnt/sdcard/). If you save data on this path and uninstall the app, that data won't be lost.
First of all, we need to understand what is difference between Internal Storage, External Storage (aka primary external storage), and Secondary External Storage?
Internal Storage: is storage that is not accessible by the user, except via installed apps (or by rooting their device). Example: data/data/app_packageName
Primary External Storage: In built shared storage which is "accessible by the user by plugging in a USB cable and mounting it as a drive on a host computer". Example: When we say Nexus 5 32 GB.
Secondary External Storage: Removable storage. Example: SD Card.
getExternalFilesDir (String type)
It returns the path to files folder inside Android/data/data/your_package/ on primary external storage. Which is inbuilt storage.
Environment.getExternalStorageDirectory()
It will return the path of the secondary external storage directory
! IMPORTANT UPDATE ! for whoever comes across this question.
As this is a somewhat old question just wanted to provide some additional information. Since KitKat even apps that have WRITE_EXTERNAL_STORAGE permission are only allowed to write to Android/data/data/your_package/ on external storage, a.k.a getExternalFilesDir()
If you will try to write to getExternalStorageDirectory() + "/somefolder/anotherfolder/" you will get a SecurityException on most devices
!! IMPORTANT !!
Environment.getExternalStorageDirectory() is deprecated and Context#getExternalFilesDir(String), MediaStore, or Intent#ACTION_OPEN_DOCUMENT, should be used instead.
This method was deprecated in API level 29.
To improve user privacy, direct access to shared/external storage devices is deprecated. When an app targets Build.VERSION_CODES.Q, the path returned from this method is no longer directly accessible to apps. Apps can continue to access content stored on shared/external storage by migrating to alternatives such as Context#getExternalFilesDir(String), MediaStore, or Intent#ACTION_OPEN_DOCUMENT.
https://developer.android.com/reference/android/os/Environment.html#getExternalStorageDirectory()
Also beginning from Android.M developers need to ask for permissions at run time.
See more details in documentation here and this question
Environment.getExternalStorageDirectory() deprecated in API level 29 java

Where to save pictures on Android?

My application uses quite a lot of pictures that are downloaded from the internet and cached locally on the Android phone. I am wondering, what is the correct way to save those pictures. There are several ways I see, that are not fully satisfying.
Save them on SD Card in a public folder
Uses up space that wont be freed on uninstall
User can see pics in Gallery
Needs a folder on the sdcard root (you can actually see it while browsing your phone)
Save them on SD Card in a non-public folder
Uses up space that wont be freed on uninstall
Secretly uses space on the SD Card
Save them inside the application
Blows up application size far too much
What is the correct way of locally saving the images of my application to not distract the user and leave no garbage anywhere?
Your best solution is to use:
context.getCacheDir()
This directory is private to the application and will be deleted on uninstall, furthermore the system can delete from this directory for you if the device is running short of space.
Note though that the docs say:
you should not rely on the system
deleting these files for you; you
should always have a reasonable
maximum, such as 1 MB, for the amount
of space you consume with cache files,
and prune those files when exceeding
that space
If you need a lot of space and would rather use the SD card you can call
getExternalCacheDir()
instead. These will also get removed on uninstall, but the system does not monitor the space available in external storage, so won't automatically delete these files if low on space. If using this option you should also check that external storage is available with
Environment.getExternalStorageState()
before attempting to write to it.
You can hide images from the MediaScanner if you put it in a hidden dir (i.e., with a dot prefixed) such as /sdcard/.donotscan/.
Update: As romainguy mentions on twitter this also works if you put a file named .nomedia into the dir.
I think the best way is to use the database.
It does not blow up the application and memory.
The related database is deleted once the application is uninstalled.
Nobody can reach to this files besides your application.
Update: But; If you want to cache only the data, there is a cache manager defined in webkit. CacheManager
I didn't use the package before but the methods seem straight forward to use:
static boolean cacheDisabled()
static boolean endCacheTransaction()
static CacheManager.CacheResult getCacheFile(String url, Map<String, String> headers)
static File getCacheFileBaseDir()
static void saveCacheFile(String url, CacheManager.CacheResult cacheRet)
static boolean startCacheTransaction()
and you can find the usage at Google Gears code
I hope this helps.
If you you don't want to use the CacheManager then use a database or a local (non-SD) file (local files get deleted on a complete uninstall) and register to receive the 'ACTION_DEVICE_STORAGE_LOW' and 'ACTION_DEVICE_STORAGE_OK' broadcast actions. Then you'll know when your application is taking up too much space according to the device and when you need to start deleting pictures. Your application size will still grow, but you will be able to manage the growth and shrinkage.
Just a tip - if you save them on the SD Card, they will be scanned by the MediaScanner and will appear in the users's Gallery (Photos), which you probably don't want. So you probably want to store them on the phone, or somehow tell MediaScanner not to scan them (apparently impossible after a quick Google search.)
Probably best to store a select few in your application's private directory, which will be removed when your application is uninstalled.

Categories