I'm working on an Android application that needs to look at what images a user has stored. The problem is that if the user has the sdcard mounted via the USB cable, I can't read the list of images on the disk.
Does anyone know of a way to tell if the usb is mounted so that I could just pop up a message informing the user that it won't work?
If you're trying to access images on the device, the best method is to use the MediaStore content provider. Accessing it as a content provider will allow you to query the images that are present, and map content:// URLs to filepaths on the device where appropriate.
If you still need to access the SD card, the Camera application includes an ImageUtils class that checks if the SD card is mounted as follows:
static public boolean hasStorage(boolean requireWriteAccess) {
//TODO: After fix the bug, add "if (VERBOSE)" before logging errors.
String state = Environment.getExternalStorageState();
Log.v(TAG, "storage state is " + state);
if (Environment.MEDIA_MOUNTED.equals(state)) {
if (requireWriteAccess) {
boolean writable = checkFsWritable();
Log.v(TAG, "storage writable is " + writable);
return writable;
} else {
return true;
}
} else if (!requireWriteAccess && Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
return true;
}
return false;
}
Here is the checkFsWritable missing function in jargonjustin post
private static boolean checkFsWritable() {
// Create a temporary file to see whether a volume is really writeable.
// It's important not to put it in the root directory which may have a
// limit on the number of files.
String directoryName = Environment.getExternalStorageDirectory().toString() + "/DCIM";
File directory = new File(directoryName);
if (!directory.isDirectory()) {
if (!directory.mkdirs()) {
return false;
}
}
return directory.canWrite();
}
public static boolean isSdPresent() {
return android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);
}
I apologise for posting a non-Android way of doing this, hopefully someone can provide an answer using the Android API.
You could list the files on the root of the sdcard. If there is none, the sdcard is either entirely blank (unusual, but possible) or it is unmounted. If you try to create an empty file on the sdcard and it fails, it means that you were trying to create a file in the mount-point of the sdcard which would be denied due to a permissions issue so you would know the sdcard was not mounted.
Yes, I know this is ugly....
On jargonjustin's post:
File ImageManager.java
Method hasStorage -->
public static boolean hasStorage(boolean requireWriteAccess) {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
if (requireWriteAccess) {
boolean writable = checkFsWritable();
return writable;
} else {
return true;
}
} else if (!requireWriteAccess
&& Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
return true;
}
return false;
}
Method checkFsWritable -->
private static boolean checkFsWritable() {
// Create a temporary file to see whether a volume is really writeable.
// It's important not to put it in the root directory which may have a
// limit on the number of files.
String directoryName =
Environment.getExternalStorageDirectory().toString() + "/DCIM";
File directory = new File(directoryName);
if (!directory.isDirectory()) {
if (!directory.mkdirs()) {
return false;
}
}
File f = new File(directoryName, ".probe");
try {
// Remove stale file if any
if (f.exists()) {
f.delete();
}
if (!f.createNewFile()) {
return false;
}
f.delete();
return true;
} catch (IOException ex) {
return false;
}
}
I was using cursor for retrieving the images from sd card and when no sd card was inserted in device the cursor was null.
Actually this is the case when the sdcard volume was unmounted by physically removing card from device. This is the code I've used:
Cursor mCursor = this.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null, null, null);
if (mCursor == null || !mCursor .moveToFirst()) {
/**
*mCursor == null:
* - query failed; the app don't have access to sdCard; example: no sdCard
*
*!mCursor.moveToFirst():
* - there is no media on the device
*/
} else {
// process the images...
mCursor.close();
}
More info: http://developer.android.com/guide/topics/media/mediaplayer.html#viacontentresolver
Before you do any work with the external storage, you should always call getExternalStorageState() to check whether the media is available. The media might be mounted to a computer, missing, read-only, or in some other state. For example, here are a couple methods you can use to check the availability:
/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
/* Checks if external storage is available to at least read */
public boolean isExternalStorageReadable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state) ||
Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
return true;
}
return false;
}
source:
http://developer.android.com/guide/topics/data/data-storage.html
Cool....Check it out...
try {
File mountFile = new File("/proc/mounts");
usbFoundCount=0;
sdcardFoundCount=0;
if(mountFile.exists())
{
Scanner usbscanner = new Scanner(mountFile);
while (usbscanner.hasNext()) {
String line = usbscanner.nextLine();
if (line.startsWith("/dev/fuse /storage/usbcard1")) {
usbFoundCount=1;
Log.i("-----USB--------","USB Connected and properly mounted---/dev/fuse /storage/usbcard1" );
}
}
}
if(mountFile.exists()){
Scanner sdcardscanner = new Scanner(mountFile);
while (sdcardscanner.hasNext()) {
String line = sdcardscanner.nextLine();
if (line.startsWith("/dev/fuse /storage/sdcard1")) {
sdcardFoundCount=1;
Log.i("-----USB--------","USB Connected and properly mounted---/dev/fuse /storage/sdcard1" );
}
}
}
if(usbFoundCount==1)
{
Toast.makeText(context,"USB Connected and properly mounted", 7000).show();
Log.i("-----USB--------","USB Connected and properly mounted" );
}
else
{
Toast.makeText(context,"USB not found!!!!", 7000).show();
Log.i("-----USB--------","USB not found!!!!" );
}
if(sdcardFoundCount==1)
{
Toast.makeText(context,"SDCard Connected and properly mounted", 7000).show();
Log.i("-----SDCard--------","SDCard Connected and properly mounted" );
}
else
{
Toast.makeText(context,"SDCard not found!!!!", 7000).show();
Log.i("-----SDCard--------","SDCard not found!!!!" );
}
}catch (Exception e) {
e.printStackTrace();
}
Related
My app runs on Android 5.0. I use method getExternalFilesDirs() to check if external SD card is available. If it returns more than 1 File, that means external SD card exists.
But on some devices (for example Elephone G2), method getExternalFilesDirs() returns only one directory of primary storage. I'm sure that device has external SD card (/storage/sdcard1/).
Can any one give me the answer?
For getExternalFilesDirs to return the path of the sdcard, the OEM must have set the SECONDARY_STORAGE environment variable in the device specific init.rc file as mentioned here:
https://source.android.com/devices/storage/config-example.html
Look at the source of getExternalFilesDirs here:
http://androidxref.com/5.1.1_r6/xref/frameworks/base/core/java/android/app/ContextImpl.java#1039
The value is obtained from Environment.buildExternalStorageAppFilesDirs. Look at that source here:
http://androidxref.com/5.1.1_r6/xref/frameworks/base/core/java/android/os/Environment.java#206
The value is dependent on mExternalDirsForApp, which in turn is populated by reading the contents of SECONDARY_STORAGE variable:
http://androidxref.com/5.1.1_r6/xref/frameworks/base/core/java/android/os/Environment.java#136
As you can see, if the SECONDARY_STORAGE variable is not set, the sdcard path will not be returned.
You can cross-check this by going to adb shell and looking at the output of echo $SECONDARY_STORAGE
In my projects using this code & i don't have any problem.
method of getExternalFilesDirs return array with 2 length.
Dirs[0] ==> Internal Sorage
Dirs[1] ==> External Storage
File[] Dirs = ContextCompat.getExternalFilesDirs(MyApp.GetContext(), null);
this issue there is in some of Lenovo device too.
my solution is this.
String EXTERNAL_SD_PATH1;
String EXTERNAL_SD_PATH2;
public boolean hasExternalSDCard()
{
try
{
String state = Environment.getExternalStorageState();
if(Environment.MEDIA_MOUNTED.equals(state) || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state))
return true;
}
catch (Throwable e)
{}
return false;
}
#SuppressLint("SdCardPath")
protected synchronized void _prepareStorage()
{
EXTERNAL_SD_PATH1 = null;
EXTERNAL_SD_PATH2 = null;
if (hasExternalSDCard())
{
try
{
if(VERSION_SDK_INT > 18)
{
Context context = getContext();
File[] sds = getExternalFilesDirs("");
if(sds == null)
return;
if(sds.length >= 2)
{
EXTERNAL_SD_PATH1 = TextWorker.getSubStringBeforeLastMark(sds[1].getAbsolutePath(),"/Android/");
if(sds.length > 2)
EXTERNAL_SD_PATH2 = TextWorker.getSubStringBeforeLastMark(sds[2].getAbsolutePath(),"/Android/");
}
else
{
String internal = sds[0].getAbsolutePath();
internal = TextWorker.getSubStringBeforeLastMark(internal,"/Android/");
int len = internal.length();
int num = Integer.valueOf(internal.substring(len - 1));
String ex1 = internal.substring(0, len-1) + (num+1);
File sd1 = new File(ex1);
if(sd1.exists())
EXTERNAL_SD_PATH1 = sd1.getAbsolutePath();
String ex2 = internal.substring(0, len-1) + (num+2);
File sd2 = new File(ex2);
if(sd2.exists())
EXTERNAL_SD_PATH2 = sd2.getAbsolutePath();
}
}
else
{
File sd = Environment.getExternalStorageDirectory();
String path = sd.getAbsolutePath();
if (sd.exists() && (path.contains("/mnt/") || path.contains("/storage") || path.contains("/sdcard")) && (!path.contains("emulate")))
{
EXTERNAL_SD_PATH1 = path;
}
}
}
catch (Throwable e)
{}
}
}
public static String getSubStringBeforeLastMark(String str,String mark)
{
int l = str.lastIndexOf(mark);
if(l == -1 || l == 0)
return "";
return str.substring(0, l);
}
I have this code, that should be executed, when SD card is removed from an Android device (by remove, I understand, that user selects remove from Android device menu or configuration, just as you remove USB device or SD card from any other system, before phisically removing the card):
public void kartkontrol()
{
String state = android.os.Environment.getExternalStorageState();
if (state.equals(android.os.Environment.MEDIA_MOUNTED))
{
// We can read and write the media
Durum=" Hafıza Kartı Var (Okuma/Yazma)";
}
else if (android.os.Environment.MEDIA_MOUNTED_READ_ONLY.equals(state))
{
// We can only read the media
Durum=" Hafıza Kartı Var (Okuma İzni)";
}
else
{
// No external media
Durum=" Hafıza Kartı Yok";
}
}
Card should be uninstalled and removed, but it seems, that it is actually installed during this process.
What am I doing wrong?
You can find further information in the Android documentation.
There is a nice post here talking about detecting mounted sd card via USB.
you can also use this useful method instead :
static public boolean hasStorage(boolean requireWriteAccess) {
//TODO: After fix the bug, add "if (VERBOSE)" before logging errors.
String state = Environment.getExternalStorageState();
Log.v(TAG, "storage state is " + state);
if (Environment.MEDIA_MOUNTED.equals(state)) {
if (requireWriteAccess) {
boolean writable = checkFsWritable();
Log.v(TAG, "storage writable is " + writable);
return writable;
} else {
return true;
}
} else if (!requireWriteAccess && Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
return true;
}
return false;
}
code when I remove the card is mounted, but it must be unmounted. I solved this problem with another code. running smoothly. no problem
sSDpath = null;
fileCur = null;
for (String sPathCur : Arrays.asList("ext_card", "external_sd", "ext_sd", "external","extSdCard", "externalSdCard")) // external sdcard
{
fileCur = new File("/mnt/", sPathCur);
if (fileCur.isDirectory() && fileCur.canWrite()) {
sSDpath = fileCur.getAbsolutePath();
kartk.setText("Hafıza Kartı Takılı");
Toast.makeText(getApplicationContext(), "kkkBirinci", Toast.LENGTH_LONG).show();
break;
}
}
fileCur = null;
if (sSDpath == null) {
sSDpath = Environment.getExternalStorageDirectory().getAbsolutePath();
kartk.setText("Hafıza Kartı Takılı Değil");
Toast.makeText(getApplicationContext(), "kkkikinci", Toast.LENGTH_LONG).show();
}
I swear I've seen this done in other apps, but I can't think of any examples:
I would like to check if my app has been granted root or not (not request). If not, I would like to explain what's about to happen BEFORE requesting root (triggering the super user dialogue box).
Is there any way to do this? The only thing I can think of is to save a preference indicating that they've read the explanation before I check, but that's not ideal. Suggestions?
Try this piece of code:
/**
* Checks if the device is rooted.
*
* #return <code>true</code> if the device is rooted, <code>false</code> otherwise.
*/
public static boolean isRooted() {
// get from build info
String buildTags = android.os.Build.TAGS;
if (buildTags != null && buildTags.contains("test-keys")) {
return true;
}
// check if /system/app/Superuser.apk is present
try {
File file = new File("/system/app/Superuser.apk");
if (file.exists()) {
return true;
}
} catch (Exception e1) {
// ignore
}
// try executing commands
return canExecuteCommand("/system/xbin/which su")
|| canExecuteCommand("/system/bin/which su") || canExecuteCommand("which su");
}
// executes a command on the system
private static boolean canExecuteCommand(String command) {
boolean executedSuccesfully;
try {
Runtime.getRuntime().exec(command);
executedSuccesfully = true;
} catch (Exception e) {
executedSuccesfully = false;
}
return executedSuccesfully;
}
I'm currently developing a live wallpaper that reads from external storage.
When the device is booting up, I assume it's possible for the live wallpaper to be launched before the storage is ready. Especially if its doing the periodic error check. Others are reporting issues and I think this is the reason. I can't seem to test this, because the external storage seems to mount instantly on my device, and I'm not sure how to force it to do the error check. So my first question is, does the system actually way for the BOOT_COMPLETED intent before it launches the live wallpaper.
If not, what is the proper way to wait for the external storage to be ready. I'm thinking of calling something like this in the beginning of the app
public void waitForExternalStorage()
{
while(Environment.getExternalStorageState().equals(Environment.MEDIA_CHECKING))
{
try { Thread.sleep(1000L); }
catch(InterruptedException e) { e.printStackTrace(); }
}
}
Do I have to check for other cases, in case it goes MEDIA_REMOVED -> MEDIA_UNMOUNTED -> MEDIA_CHECKING(optional) -> MEDIA_READY on boot?
You can register a BroadcastReceiver to listen to changes in the external storage state:
BroadcastReceiver externalStorageStateReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
updateExternalStorageState();
}
};
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_MEDIA_MOUNTED);
filter.addAction(Intent.ACTION_MEDIA_REMOVED);
registerReceiver(mExternalStorageReceiver, filter);
updateExternalStorageState(); // You can initialize the state here, before any change happens
And in updateExternalStorageState() you can check the actual state after the change:
protected void updateExternalStorageState() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
// SD card is mounted and ready for use
} else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
// SD card is mounted, but it is read only
} else {
// SD card is unavailable
}
}
use broadcast receiver, listen for Intent.ACTION_MEDIA_MOUNTED : Broadcast Action: External media is present and mounted at its mount point.
I needed exactly that. I am reading a configuration file from the SD card and my on-boot running app simply cannot run without reading it. A simple solution is to wait a maximum of 15-30 seconds for the SD card to be automatically mounted by the Android OS. If not, throw an exception. Here's the code. Just increase the max count limit to increase the wait time. The ExternalStorageNotReadyException is a custom exception.
public void awaitExternalStorageInitialization()
throws ExternalStorageNotReadyException {
boolean mExternalStorageAvailable = false;
boolean mExternalStorageWriteable = false;
int count = 0;
do {
String state = Environment.getExternalStorageState();
if(count > 0) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
Log.e(Constants.LOG_TAG, e.getMessage(), e);
}
}
if (Environment.MEDIA_MOUNTED.equals(state)) {
// We can read and write the media
mExternalStorageAvailable = mExternalStorageWriteable = true;
} else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
// We can only read the media
mExternalStorageAvailable = true;
mExternalStorageWriteable = false;
} else {
// Something else is wrong. It may be one of many other states,
// but all we need
// to know is we can neither read nor write
mExternalStorageAvailable = mExternalStorageWriteable = false;
}
count++;
} while ((!mExternalStorageAvailable) && (!mExternalStorageWriteable) && (count < 5));
if(!mExternalStorageWriteable)
throw new ExternalStorageNotReadyException("External storage device (SD Card) not yet ready");
}
I'm working on an Android application that needs to look at what images a user has stored. The problem is that if the user has the sdcard mounted via the USB cable, I can't read the list of images on the disk.
Does anyone know of a way to tell if the usb is mounted so that I could just pop up a message informing the user that it won't work?
If you're trying to access images on the device, the best method is to use the MediaStore content provider. Accessing it as a content provider will allow you to query the images that are present, and map content:// URLs to filepaths on the device where appropriate.
If you still need to access the SD card, the Camera application includes an ImageUtils class that checks if the SD card is mounted as follows:
static public boolean hasStorage(boolean requireWriteAccess) {
//TODO: After fix the bug, add "if (VERBOSE)" before logging errors.
String state = Environment.getExternalStorageState();
Log.v(TAG, "storage state is " + state);
if (Environment.MEDIA_MOUNTED.equals(state)) {
if (requireWriteAccess) {
boolean writable = checkFsWritable();
Log.v(TAG, "storage writable is " + writable);
return writable;
} else {
return true;
}
} else if (!requireWriteAccess && Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
return true;
}
return false;
}
Here is the checkFsWritable missing function in jargonjustin post
private static boolean checkFsWritable() {
// Create a temporary file to see whether a volume is really writeable.
// It's important not to put it in the root directory which may have a
// limit on the number of files.
String directoryName = Environment.getExternalStorageDirectory().toString() + "/DCIM";
File directory = new File(directoryName);
if (!directory.isDirectory()) {
if (!directory.mkdirs()) {
return false;
}
}
return directory.canWrite();
}
public static boolean isSdPresent() {
return android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED);
}
I apologise for posting a non-Android way of doing this, hopefully someone can provide an answer using the Android API.
You could list the files on the root of the sdcard. If there is none, the sdcard is either entirely blank (unusual, but possible) or it is unmounted. If you try to create an empty file on the sdcard and it fails, it means that you were trying to create a file in the mount-point of the sdcard which would be denied due to a permissions issue so you would know the sdcard was not mounted.
Yes, I know this is ugly....
On jargonjustin's post:
File ImageManager.java
Method hasStorage -->
public static boolean hasStorage(boolean requireWriteAccess) {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
if (requireWriteAccess) {
boolean writable = checkFsWritable();
return writable;
} else {
return true;
}
} else if (!requireWriteAccess
&& Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
return true;
}
return false;
}
Method checkFsWritable -->
private static boolean checkFsWritable() {
// Create a temporary file to see whether a volume is really writeable.
// It's important not to put it in the root directory which may have a
// limit on the number of files.
String directoryName =
Environment.getExternalStorageDirectory().toString() + "/DCIM";
File directory = new File(directoryName);
if (!directory.isDirectory()) {
if (!directory.mkdirs()) {
return false;
}
}
File f = new File(directoryName, ".probe");
try {
// Remove stale file if any
if (f.exists()) {
f.delete();
}
if (!f.createNewFile()) {
return false;
}
f.delete();
return true;
} catch (IOException ex) {
return false;
}
}
I was using cursor for retrieving the images from sd card and when no sd card was inserted in device the cursor was null.
Actually this is the case when the sdcard volume was unmounted by physically removing card from device. This is the code I've used:
Cursor mCursor = this.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, null, null, null, null);
if (mCursor == null || !mCursor .moveToFirst()) {
/**
*mCursor == null:
* - query failed; the app don't have access to sdCard; example: no sdCard
*
*!mCursor.moveToFirst():
* - there is no media on the device
*/
} else {
// process the images...
mCursor.close();
}
More info: http://developer.android.com/guide/topics/media/mediaplayer.html#viacontentresolver
Before you do any work with the external storage, you should always call getExternalStorageState() to check whether the media is available. The media might be mounted to a computer, missing, read-only, or in some other state. For example, here are a couple methods you can use to check the availability:
/* Checks if external storage is available for read and write */
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
/* Checks if external storage is available to at least read */
public boolean isExternalStorageReadable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state) ||
Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
return true;
}
return false;
}
source:
http://developer.android.com/guide/topics/data/data-storage.html
Cool....Check it out...
try {
File mountFile = new File("/proc/mounts");
usbFoundCount=0;
sdcardFoundCount=0;
if(mountFile.exists())
{
Scanner usbscanner = new Scanner(mountFile);
while (usbscanner.hasNext()) {
String line = usbscanner.nextLine();
if (line.startsWith("/dev/fuse /storage/usbcard1")) {
usbFoundCount=1;
Log.i("-----USB--------","USB Connected and properly mounted---/dev/fuse /storage/usbcard1" );
}
}
}
if(mountFile.exists()){
Scanner sdcardscanner = new Scanner(mountFile);
while (sdcardscanner.hasNext()) {
String line = sdcardscanner.nextLine();
if (line.startsWith("/dev/fuse /storage/sdcard1")) {
sdcardFoundCount=1;
Log.i("-----USB--------","USB Connected and properly mounted---/dev/fuse /storage/sdcard1" );
}
}
}
if(usbFoundCount==1)
{
Toast.makeText(context,"USB Connected and properly mounted", 7000).show();
Log.i("-----USB--------","USB Connected and properly mounted" );
}
else
{
Toast.makeText(context,"USB not found!!!!", 7000).show();
Log.i("-----USB--------","USB not found!!!!" );
}
if(sdcardFoundCount==1)
{
Toast.makeText(context,"SDCard Connected and properly mounted", 7000).show();
Log.i("-----SDCard--------","SDCard Connected and properly mounted" );
}
else
{
Toast.makeText(context,"SDCard not found!!!!", 7000).show();
Log.i("-----SDCard--------","SDCard not found!!!!" );
}
}catch (Exception e) {
e.printStackTrace();
}