After reading Android documentation and Stackoverflow discussion about all storage types,
and after viewing filesystems on a number of android devices, I'm a bit cofused.
Given the following results-
getFilesDir() - returns /data/data..
getExternalFilesDir() - returns /mnt/sdcard/Android/data/<ap_name>/files
getExternalStorageDirectory() - returns /mnt/sdcard/
And given the fact that the file system Windows shows me when I'm connecting my device using USB:
device\Card - contains DCIM, Images (folders) ...
device\Phone - contains WhatsApp, PicArts, Pou (apps folders) ...
And given the fact that when openning My Files app, the path is /sdcard/ and it contains all the apps folder (WhatsApp, PicsArts..),
There are things I do not understand, such as:
How come the Device/Phone contain what /mnt/sdcard/ contains? why isn't it contained in Device/Card?
are those results mean that all those known apps use the external storage as the default storage type for media files?
My intention is to create and maintain a directory in the android file system and to store media files in there.
I want this folder to be placed where all the other apps place their folder , in this case is /sdcard/ as shown in My Files app (or /mnt/sdcard as the full path), but I dont want it to be depend on whether or not the device have an availble external storage.
What should I do?
Few remarks regarding storage :
there is no guaranty that the absolute path for getExternalFilesDir() will be the same on all devices
there is no guaranty that the absolute path for getFilesDir() will be the same on all devices
there is no guaranty that the absolute path for getExternalStorageDirectory() will be the same on all devices
So don't rely on hardcoded absolute path in your code if you need that your app run on different devices.
Every Android device have 2 storage space (mainly for historical reason) : the internal and the external.
Major differences between them :
internal storage :
always available
case sensitive file system
not accessible from a PC connected by USB (for a normal user)
accessible with getFilesDir()
files stored there are private to your app
external storage :
not always available : especially after reboot it takes some time to mount the external storage; or on some devices, when the device is connected to a PC with an USB cable; or when the user has removed the microSD.
case insensitive file system
accessible in windows explorer when connected to a PC
accessible with the api getExternalFilesDir() (to get a directory dedicated to your app) or getExternalStorageDirectory() to get the root of the external storage.
Remark about external storage : today, many vendors use a virtual external storage. i.e. there is no removable sd-card; but instead there is a partition of the internal memory that is mounted as if it was an external storage (so even on those devices the external storage is not available just after a reboot).
I want this folder to be placed where all the other apps place their folder
There is no such place. All the other apps are free to put their data either on the internal storage or on the external storage.
How come the Device/Phone contain what /mnt/sdcard/ contains? why isn't it contained in Device/Card?
Only external storage is visible when your device is USB-connected. The path Device/Phone is choose by the the usb driver (and so not really relevant). The important thing is that under this path you only see the content of root external storage (i.e. the content of the directory returned by getExternalStorageDirectory())
In my Apps I always use:
fileMedia = Environment.getExternalStorageDirectory().getAbsolutePath() + "/yourappdirectoryonsdcard/" + "MediaFileName.3gpp";
File outFile = new File(fileMedia);
if (outFile.exists()) {
outFile.delete();
}
and don't have problems with available external storage detecting.
Related
When I print the SD Storage path using Environment.getExternalStorageDirectory();, it returns storage/emulated/0
but when I use DDMS to browse SD Storage there is no such directory at all. The available directory is storage/emulated/legacy
Why Environment.getExternalStorageDirectory(); shows path which doesn't even exist ?
The path exists for your app's process.
Android, starting with 4.2, supports multiple accounts per device (originally just for tablets, now for all devices starting with 5.0). Each account gets its own distinct area for internal and external storage. The framework will return paths from methods like getExternalStorageDirectory() that are correct for the current account holder that is running your app. What these locations map to in terms of actual filesystem locations is up to Android, as part of its effort to secure access to storage.
I read alot about KITKAT and the prevention of writing to the secondary external sdcard.
It seems to be a new policy from google. I also read about storing the app's data under /externalsdcard/Android/data/.
Now my question, because I can't reproduce or test:
If the app is not allowed to write data directly under
< secundary external sdcard >, Will it then be possible to store the app's data under < secundary external sdcard >/Android/data/< app package name > ?
If possible. Could someone share a codesample ?
Never assume the removable secondary storage is larger than primar internal. On most modern devices internal storage can be up to 64 GB, but SD Card can be as small as 1 MB large (if user inserted small old card).
There is no way to distinguish which one is "external" using current APIs.
So the right way is using Context.getExternalFilesDirs() which returns all external storages to which you can store application-specific files without any permissions.
Use StatFs to find the largest storage available, and write data into it.
final File[] dirs = context.getExternalFilesDirs(null); //null means default type
//find a dir that has most of the space and save using StatFs
As the documentation says,
Returns absolute paths to application-specific directories on all external storage devices where the application can place persistent files it owns. These files are internal to the application, and not typically visible to the user as media.
This is like getFilesDir() in that these files will be deleted when the application is uninstalled, however there are some important differences:
External files are not always available: they will disappear if the user mounts the external storage on a computer or removes it.
There is no security enforced with these files.
External storage devices returned here are considered a permanent part of the device, including both emulated external storage and physical media slots, such as SD cards in a battery compartment. The returned paths do not include transient devices, such as USB flash drives.
An application may store data on any or all of the returned devices. For example, an app may choose to store large files on the device with the most available space, as measured by StatFs.
No permissions are required to read or write to the returned paths; they are always accessible to the calling app. Write access outside of these paths on secondary external storage devices is not available.
The first path returned is the same as getExternalFilesDir(String). Returned paths may be null if a storage device is unavailable.
I've an application on the Play Store, and a user sent me a bug report saying that on his device the external sdcard is not listed in the external storage device list, though is mounted and accessible at /mnt/external_sd
I have a dialog listing folders and start directory is Environment.getExternalStorageDirectory().
After some clicks to get to the parent folder, the /storage folder is reached and getParent() returns null.
Which starting folder should I set to have access to the full storage structure?
EDIT:
As a workaround I am adding in my app preference the ability to choose if the storage root directory should be Environment.getExternalStorageDirectory() or hardcoded /mnt.
Comment/answer if there are best alternatives.
Get external storage parent folder on android
By external storage, I am assuming that you meant micro SD card storage.
external sdcard is not listed in the external storage device list,
though is mounted and accessible at /mnt/external_sd
You cannot access SD storage by using Environment.getExternalStorageDirectory() method.
Before API level 19, there was no official way to store in SD card. But, many could do it using unofficial APIs.
Officially, one method was introduced in Context class in API level 19 (Android version 4.4 - Kitkat).
File[] getExternalFilesDirs (String type)
It returns absolute paths to application-specific directories on all
shared/external storage devices where the application can place
persistent files it owns. These files are internal to the application,
and not typically visible to the user as media.
That means, it will return paths to both Micro SD card and Internal memory. Generally, second returned path would be storage path of micro SD card.
The Internal and External Storage terminology according to Google/official Android docs is quite different from what we think.
When using Eclipse file explorer to navigate my android directories, I saw mnt/sdcard and mnt/sdcard2, see below image:
When callingEnvironment.getExternalStorageDirectory() it returns mnt/sdcard, so I think the mnt/sdcad is the external storage , and mnt/sdcard2 is my actual SD card, is that true? And how can I use code to access files under mnt/sdcard2 ?
P.S.
It seems that I can access the external sd card directly:
File extStorageDir = Environment.getExternalStorageDirectory();
String parent = extStorageDir.getParent();
File extSdCardDir = new File(parent+"/sdcard2");
File file = new File(extSdCardDir, "DemoFile.jpg");
But I wonder the extra sd card will change name in other cases.
You are correct, getExternalStorage will return your built-in external storage. Unfortunately, as of Jelly Bean applications are no longer able to utilize the SD card if the device also has built-in storage as well as an SD card. You can try working around it through shell commands or hardcoding paths, but without root there is no reliable way to access it anymore.
This was just recently added the Android CTS, which all OEMs must comply with in order to use the Play store.
Compatibility Program Overview | Android Developers
Section 9.5 (pg. 34) of Android 4.3 Compatibility Definition
Device implementations that include multiple external storage paths
MUST NOT allow Android applications to write to the secondary external
storage.
Storage Options | Android Developers
It's possible that a device using a partition of the internal storage
for the external storage may also offer an SD card slot. In this case,
the SD card is not part of the external storage and your app cannot
access it (the extra storage is intended only for user-provided media
that the system scans).
Android 4.2 APIs | Android Developers
Saving data in a multi-user environment
Whenever your app saves user preferences, creates a database, or
writes a file to the user’s internal or external storage space, that
data is accessible only while running as that user.
To be certain that your app behaves properly in a multi-user
environment, do not refer to your internal app directory or external
storage location using hard-coded paths and instead always use the
appropriate APIs:
For access to internal storage, use getFilesDir(), getCacheDir(), or openFileOutput().
For access to external storage, use getExternalFilesDir() or getExternalStoragePublicDirectory().
No matter which of these APIs you use to save data for a given user,
the data will not be accessible while running as a different user.
From your app’s point of view, each user is running on a completely
separate device.
So I'm testing an app on a galaxy s3 on 4.1 and an older phone that runs 2.3. Neither phone has an sdcard in it but when I use Environment.getExternalStorageDirectory().getAbsolutePath() on my galaxy s3 it directs me to a folder called sdcard0 within a folder called storage. When I run it on the older phone it gives me the path mnt/sdcard/ and the sdcard folder is read only.
I am trying to create a folder in these directories. I can do it on my s3 but not on my older phone.
Is there something similar to the storage folder I'm missing on the older phone or can I write to the sdcard folder when there is no sd card present?
EDIT: I have the external write permissions in my manifest
On some phones, as the documentation suggests, the word external is not to be taken all too serious:
Note: don't be confused by the word "external" here. This
directory can better be thought as media/shared storage. It is a
filesystem that can hold a relatively large amount of data and that
is shared across all applications (does not enforce permissions).
Traditionally this is an SD card, but it may also be implemented as built-in storage in a device that is distinct from the protected
internal storage and can be mounted as a filesystem on a computer.
You can check if the storage is really external or not, using the Environment.isExternalStorageRemovable()-method. If it's not removable, you should always be able to write to it (given that you have the permissions declared).
If it is however removable, you'll need to check it's current state with Environment.getExternalStorageState(). Here's a quick example of how to use it:
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
// We can read and write!
} else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
// Mounted read only...
} else {
// Something is wrong...
}
So in these cases, you can write to the external storage.
Important: As the documentation specifies at multiple points, the above methods work for the primary external storage. Some devices (like the Motorola Xoom) have both an internal "external" storage, and an SD-Card.
There seems to be no "generalized" way to access the "secondary external storage" on such devices, although there is a standard now, introduced with Android 4.2
Devices may contain multiple instances of external storage, but
currently only the primary external storage is exposed to developers through API.
[...]
Starting in Android 4.2, devices can support multiple users, and
external storage must meet the following constraints:
[...]
Secondary external storage must not be writable by apps.
It seems to depend on the vendor which storage (internal or real external) is considered the primary one. Not much you can do here (without things getting messy...)
If there is no external storage present, you can use your applications Internal Storage, or the caching directory, depending on what kind of data you're storing.