From 1f1aaf7c3809aaddee6902b8f3cc3b9f2e7db697 Mon Sep 17 00:00:00 2001 From: dentex Date: Tue, 5 Nov 2013 10:27:12 +0100 Subject: [PATCH 1/3] Change the download destination free-space check to include other possible mounted partitions (i.e. external/removable sdcard); --- .../android/download/DownloadTask.java | 10 +- .../android/storage/StorageUtils.java | 113 +++++++++++++++++- 2 files changed, 113 insertions(+), 10 deletions(-) diff --git a/Library/src/com/matsuhiro/android/download/DownloadTask.java b/Library/src/com/matsuhiro/android/download/DownloadTask.java index 52633b5..98aa6c5 100644 --- a/Library/src/com/matsuhiro/android/download/DownloadTask.java +++ b/Library/src/com/matsuhiro/android/download/DownloadTask.java @@ -310,13 +310,15 @@ private long download() throws NetworkErrorException, IOException, /* * check memory */ - long storage = StorageUtils.getAvailableStorage(); + String mFileStorage = StorageUtils.findStoragePathForGivenFile(mFile); + long storageSpace = StorageUtils.getAvailableStorage(mFileStorage); + if (DEBUG) { - Log.i(null, "storage:" + storage + " totalSize:" + length); + Log.v(TAG, "storageSpace: " + storageSpace + "; total file size: " + length); } - if (length - mPreviousFileSize > storage) { - throw new NoMemoryException("SD card no memory."); + if (length - mPreviousFileSize > storageSpace) { + throw new NoMemoryException("Not enough free space on destination storage."); } RandomAccessFile outputStream = new ProgressReportingRandomAccessFile(mTempFile, "rw"); diff --git a/Library/src/com/matsuhiro/android/storage/StorageUtils.java b/Library/src/com/matsuhiro/android/storage/StorageUtils.java index 33034fe..ea8698b 100644 --- a/Library/src/com/matsuhiro/android/storage/StorageUtils.java +++ b/Library/src/com/matsuhiro/android/storage/StorageUtils.java @@ -1,16 +1,27 @@ package com.matsuhiro.android.storage; +import java.io.File; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.matsuhiro.android.download.DownloadTask; + +import android.os.Build; import android.os.Environment; import android.os.StatFs; +import android.text.TextUtils; +import android.util.Log; public class StorageUtils { + + private static final String TAG = DownloadTask.class.getSimpleName(); - public static long getAvailableStorage() { - - String storageDirectory = null; - storageDirectory = Environment.getExternalStorageDirectory().toString(); - + @SuppressWarnings("deprecation") + public static long getAvailableStorage(String storageDirectory) { try { StatFs stat = new StatFs(storageDirectory); long avaliableSize = ((long) stat.getAvailableBlocks() * (long) stat.getBlockSize()); @@ -19,5 +30,95 @@ public static long getAvailableStorage() { return 0; } } + + /* method getStorageDirectories() from Stack Overflow: + * + * http://stackoverflow.com/a/18871043/1865860 + * + * Q: http://stackoverflow.com/users/290163/romulus-urakagi-tsai + * A: http://stackoverflow.com/users/2791190/dmitriy-lozenko + */ + private static final Pattern DIR_SEP = Pattern.compile("/"); -} + /** + * Raturns all available SD-Cards in the system (include emulated) + * + * Warning: Hack! Based on Android source code of version 4.3 (API 18) + * Because there is no standart way to get it. + * TODO: Test on future Android versions 4.4+ + * + * @return paths to all available SD-Cards in the system (include emulated) + */ + public static String[] getStorageDirectories() { + // Final set of paths + final Set rv = new HashSet(); + // Primary physical SD-CARD (not emulated) + final String rawExternalStorage = System.getenv("EXTERNAL_STORAGE"); + // All Secondary SD-CARDs (all exclude primary) separated by ":" + final String rawSecondaryStoragesStr = System.getenv("SECONDARY_STORAGE"); + // Primary emulated SD-CARD + final String rawEmulatedStorageTarget = System.getenv("EMULATED_STORAGE_TARGET"); + if(TextUtils.isEmpty(rawEmulatedStorageTarget)) { + // Device has physical external storage; use plain paths. + if(TextUtils.isEmpty(rawExternalStorage)) { + // EXTERNAL_STORAGE undefined; falling back to default. + rv.add("/storage/sdcard0"); + } else { + rv.add(rawExternalStorage); + } + } else { + // Device has emulated storage; external storage paths should have + // userId burned into them. + final String rawUserId; + if(Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) { + rawUserId = ""; + } else { + final String path = Environment.getExternalStorageDirectory().getAbsolutePath(); + final String[] folders = DIR_SEP.split(path); + final String lastFolder = folders[folders.length - 1]; + boolean isDigit = false; + try { + Integer.valueOf(lastFolder); + isDigit = true; + } catch(NumberFormatException ignored) { + // + } + rawUserId = isDigit ? lastFolder : ""; + } + // /storage/emulated/0[1,2,...] + if(TextUtils.isEmpty(rawUserId)) { + rv.add(rawEmulatedStorageTarget); + } else { + rv.add(rawEmulatedStorageTarget + File.separator + rawUserId); + } + } + // Add all secondary storages + if(!TextUtils.isEmpty(rawSecondaryStoragesStr)) { + // All Secondary SD-CARDs splited into array + final String[] rawSecondaryStorages = rawSecondaryStoragesStr.split(File.pathSeparator); + Collections.addAll(rv, rawSecondaryStorages); + } + return rv.toArray(new String[rv.size()]); + } + + private static String findMatch(String text, String regEx) { + Pattern pattern = Pattern.compile(regEx); + Matcher matcher = pattern.matcher(text); + if (matcher.find()) return matcher.group(); + return ""; + } + + public static String findStoragePathForGivenFile(File file) { + String[] storages = getStorageDirectories(); + String path = file.getAbsolutePath(); + + String storageInUse = null; + + for (int i = 0; i < storages.length; i++) { + String test = findMatch(path, storages[i]); + if (!test.equals("")) storageInUse = test; + } + Log.d(TAG, "storageInUse: " + storageInUse); + return storageInUse; + } +} \ No newline at end of file From 0acb9a5a4de2c21b482fe10b343be0363feae936 Mon Sep 17 00:00:00 2001 From: dentex Date: Tue, 5 Nov 2013 17:53:39 +0100 Subject: [PATCH 2/3] Update StorageUtils.java Better support for other sdcard paths. --- .../android/storage/StorageUtils.java | 49 +++++++++++++++---- 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/Library/src/com/matsuhiro/android/storage/StorageUtils.java b/Library/src/com/matsuhiro/android/storage/StorageUtils.java index ea8698b..2262436 100644 --- a/Library/src/com/matsuhiro/android/storage/StorageUtils.java +++ b/Library/src/com/matsuhiro/android/storage/StorageUtils.java @@ -22,6 +22,7 @@ public class StorageUtils { @SuppressWarnings("deprecation") public static long getAvailableStorage(String storageDirectory) { + try { StatFs stat = new StatFs(storageDirectory); long avaliableSize = ((long) stat.getAvailableBlocks() * (long) stat.getBlockSize()); @@ -101,24 +102,52 @@ public static String[] getStorageDirectories() { return rv.toArray(new String[rv.size()]); } - private static String findMatch(String text, String regEx) { + private static boolean matchFound(String text, String regEx) { Pattern pattern = Pattern.compile(regEx); Matcher matcher = pattern.matcher(text); - if (matcher.find()) return matcher.group(); - return ""; + if (matcher.find()) return true; + return false; + } + + public static String[] getAlternateStorageDirectories() { + return new String[] { "/emmc", + "/mnt/sdcard/external_sd", + "/mnt/external_sd", + "/sdcard/sd", + "/mnt/sdcard/bpemmctest", + "/mnt/sdcard/_ExternalSD", + "/mnt/sdcard-ext", + "/mnt/Removable/MicroSD", + "/Removable/MicroSD", + "/mnt/external1", + "/mnt/extSdCard", + "/mnt/extsd", + "/mnt/usb_storage", + "/mnt/extSdCard", + "/mnt/UsbDriveA", + "/mnt/UsbDriveB", }; } public static String findStoragePathForGivenFile(File file) { - String[] storages = getStorageDirectories(); + String path = file.getAbsolutePath(); - String storageInUse = null; + String[] storages = getStorageDirectories(); + for (int i = 0; i < storages.length; i++) { + if (matchFound(path, storages[i])) { + Log.d(TAG, "storageInUse: " + storages[i]); + return storages[i]; + } + } + String[] alt_storages = getAlternateStorageDirectories(); for (int i = 0; i < storages.length; i++) { - String test = findMatch(path, storages[i]); - if (!test.equals("")) storageInUse = test; + if (matchFound(path, alt_storages[i])) { + Log.d(TAG, "storageInUse: " + alt_storages[i]); + return alt_storages[i]; + } } - Log.d(TAG, "storageInUse: " + storageInUse); - return storageInUse; + + return Environment.getExternalStorageDirectory().getPath(); } -} \ No newline at end of file +} From f3c4e92482e078a45c4615a79d88b8f1ec25d9b5 Mon Sep 17 00:00:00 2001 From: dentex Date: Tue, 5 Nov 2013 18:16:26 +0100 Subject: [PATCH 3/3] small fix --- .../src/com/matsuhiro/android/storage/StorageUtils.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Library/src/com/matsuhiro/android/storage/StorageUtils.java b/Library/src/com/matsuhiro/android/storage/StorageUtils.java index 2262436..dace761 100644 --- a/Library/src/com/matsuhiro/android/storage/StorageUtils.java +++ b/Library/src/com/matsuhiro/android/storage/StorageUtils.java @@ -110,7 +110,9 @@ private static boolean matchFound(String text, String regEx) { } public static String[] getAlternateStorageDirectories() { - return new String[] { "/emmc", + return new String[] { + "/mnt/sdcard", + "/emmc", "/mnt/sdcard/external_sd", "/mnt/external_sd", "/sdcard/sd", @@ -123,6 +125,7 @@ public static String[] getAlternateStorageDirectories() { "/mnt/extSdCard", "/mnt/extsd", "/mnt/usb_storage", + "/extSdCard", "/mnt/extSdCard", "/mnt/UsbDriveA", "/mnt/UsbDriveB", }; @@ -141,7 +144,7 @@ public static String findStoragePathForGivenFile(File file) { } String[] alt_storages = getAlternateStorageDirectories(); - for (int i = 0; i < storages.length; i++) { + for (int i = 0; i < alt_storages.length; i++) { if (matchFound(path, alt_storages[i])) { Log.d(TAG, "storageInUse: " + alt_storages[i]); return alt_storages[i];