From 2e542df55715dff22c21def058bea551ee9569d0 Mon Sep 17 00:00:00 2001 From: David Calhoun Date: Thu, 23 Jul 2026 11:16:12 -0400 Subject: [PATCH 1/2] fix: read EXIF orientation directly for plain file paths MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit getImageOrientation prefixed non-content paths with "content://media" and queried the MediaStore content provider first, falling back to EXIF when that failed. For a plain filesystem path pointing at an existing file (e.g. an app cache file), that constructed Uri is never resolvable and the query always fails — on some devices by throwing IllegalArgumentException ("Volume data not found"), which was logged as an error with a stack trace on every call. Such files carry their orientation only in EXIF, so read it directly and skip the doomed provider query. MediaStore-style paths (which do not exist on the filesystem) keep the previous behavior. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../main/java/org/wordpress/android/util/ImageUtils.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/WordPressUtils/src/main/java/org/wordpress/android/util/ImageUtils.java b/WordPressUtils/src/main/java/org/wordpress/android/util/ImageUtils.java index fed838316..1fc97d37e 100644 --- a/WordPressUtils/src/main/java/org/wordpress/android/util/ImageUtils.java +++ b/WordPressUtils/src/main/java/org/wordpress/android/util/ImageUtils.java @@ -90,6 +90,14 @@ public static int getImageOrientation(Context ctx, String filePath) { filePath = filePath.replace("file://", ""); if (!filePath.contains("content://")) { + // A plain filesystem path pointing at an existing file (e.g. an app cache file) is not + // resolvable through the MediaStore content provider — prefixing it with + // "content://media" would produce a bogus Uri whose query always fails (throwing on + // some devices). EXIF is the only orientation source such a file has, so read it + // directly. + if (new File(filePath).exists()) { + return getExifOrientation(filePath); + } curStream = Uri.parse("content://media" + filePath); } else { curStream = Uri.parse(filePath); From f375205024780f54c4b6e4e834ae1bbace69322a Mon Sep 17 00:00:00 2001 From: David Calhoun Date: Wed, 19 Aug 2026 14:22:57 -0400 Subject: [PATCH 2/2] fix: decode percent-encoded paths before the EXIF orientation check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The plain-file fast path compared the raw string against the filesystem, so a percent-encoded path never matched: stripping the scheme from "file:///sdcard/My%20Photo.jpg" leaves "/sdcard/My%20Photo.jpg", which names no file, and the call fell through to the MediaStore query this fast path exists to avoid — logging the same error with a stack trace on every call. getImageOrientation already strips a "file://" prefix, and getWPImageSpanThumbnailFromFilePath parses its input as a Uri before passing it here, so URI-shaped arguments are expected input rather than a hypothetical. Try the decoded path as well as the raw one, so a filename containing a literal '%' still resolves undecoded. Co-Authored-By: Claude Opus 5 (1M context) --- .../org/wordpress/android/util/ImageUtils.java | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/WordPressUtils/src/main/java/org/wordpress/android/util/ImageUtils.java b/WordPressUtils/src/main/java/org/wordpress/android/util/ImageUtils.java index 1fc97d37e..1f7b9d4e2 100644 --- a/WordPressUtils/src/main/java/org/wordpress/android/util/ImageUtils.java +++ b/WordPressUtils/src/main/java/org/wordpress/android/util/ImageUtils.java @@ -95,8 +95,9 @@ public static int getImageOrientation(Context ctx, String filePath) { // "content://media" would produce a bogus Uri whose query always fails (throwing on // some devices). EXIF is the only orientation source such a file has, so read it // directly. - if (new File(filePath).exists()) { - return getExifOrientation(filePath); + String existingPath = firstExistingPath(filePath, Uri.decode(filePath)); + if (existingPath != null) { + return getExifOrientation(existingPath); } curStream = Uri.parse("content://media" + filePath); } else { @@ -123,6 +124,17 @@ public static int getImageOrientation(Context ctx, String filePath) { return orientation; } + /** + * Returns the first candidate that names a file on disk, or null when none of them do. + */ + private static String firstExistingPath(String... candidates) { + for (String candidate : candidates) { + if (!TextUtils.isEmpty(candidate) && new File(candidate).exists()) { + return candidate; + } + } + return null; + } private static int getExifOrientation(String path) { if (TextUtils.isEmpty(path)) {