diff --git a/android/src/com/mapswithme/maps/settings/StoragePathManager.java b/android/src/com/mapswithme/maps/settings/StoragePathManager.java index 90e84b9feb..c0a22a3d40 100644 --- a/android/src/com/mapswithme/maps/settings/StoragePathManager.java +++ b/android/src/com/mapswithme/maps/settings/StoragePathManager.java @@ -141,6 +141,9 @@ public class StoragePathManager } // Add the trailing separator because the native code assumes that all paths have it. path = StorageUtils.addTrailingSeparator(path); + // Ensure we check the same path we save into storages list later. + dir = new File(path); + final boolean isCurrent = path.equals(configPath); final long totalSize = dir.getTotalSpace(); final long freeSize = dir.getUsableSpace(); @@ -213,8 +216,13 @@ public class StoragePathManager Logger.w(TAG, "Not a directory: " + commentedPath); return; } - if (!dir.canWrite() || Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) + + // For writability check use a test dir creation instead of canWrite() to get more information + // and avoid possible false negatives. + if (!StorageUtils.isDirWritable(dir)) { + if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) + Logger.w(TAG, "Mounted read-only: " + commentedPath); isReadonly = true; commentedPath = "read-only " + commentedPath; } diff --git a/android/src/com/mapswithme/util/StorageUtils.java b/android/src/com/mapswithme/util/StorageUtils.java index 93b8b906e7..1795f726d9 100644 --- a/android/src/com/mapswithme/util/StorageUtils.java +++ b/android/src/com/mapswithme/util/StorageUtils.java @@ -31,6 +31,43 @@ public class StorageUtils { private static final String TAG = StorageUtils.class.getSimpleName(); + public static boolean isDirWritable(File dir) + { + final String path = dir.getPath(); + Logger.d(TAG, "Checking for writability " + path); + if (!dir.isDirectory()) + { + Logger.w(TAG, "Not a directory: " + path); + return false; + } + + // Extra logging to facilitate debugging writability issues, + // e.g. https://github.com/organicmaps/organicmaps/issues/2684 + if (!dir.exists()) + Logger.w(TAG, "Not exists: " + path); + if (!dir.canWrite()) + Logger.w(TAG, "Not writable: " + path); + if (!dir.canRead()) + Logger.w(TAG, "Not readable: " + path); + if (dir.list() == null) + Logger.w(TAG, "Not listable: " + path); + + final File newDir = new File(dir, "om_test_dir"); + final String newPath = newDir.getPath(); + if (!newDir.mkdir()) + Logger.w(TAG, "Failed to create the test dir: " + newPath); + if (!newDir.exists()) + { + Logger.w(TAG, "The test dir doesn't exist: " + newPath); + return false; + } + + if (!newDir.delete()) + Logger.w(TAG, "Failed to delete the test dir: " + newPath); + + return true; + } + @NonNull public static String getApkPath(@NonNull Application application) { @@ -166,7 +203,10 @@ public class StorageUtils { File[] list = dir.listFiles(); if (list == null) + { + Logger.w(TAG, "listFilesRecursively listFiles() returned null for " + dir.getPath()); return; + } for (File file : list) { @@ -189,7 +229,7 @@ public class StorageUtils final File[] list = dir.listFiles(); if (list == null) { - Logger.w(TAG, "getDirSizeRecursively dirFiles returned null"); + Logger.w(TAG, "getDirSizeRecursively listFiles() returned null for " + dir.getPath()); return 0; }