diff --git a/modules/juce_core/native/juce_android_Files.cpp b/modules/juce_core/native/juce_android_Files.cpp index 75c52a18d1..a4c3458d4e 100644 --- a/modules/juce_core/native/juce_android_Files.cpp +++ b/modules/juce_core/native/juce_android_Files.cpp @@ -137,6 +137,28 @@ public: return getCursorDataColumn (url); } + + static String getFileNameFromContentUri (const URL& url) + { + auto uri = urlToUri (url); + auto* env = getEnv(); + LocalRef contentResolver (android.activity.callObjectMethod (JuceAppActivity.getContentResolver)); + + if (contentResolver == 0) + return {}; + + auto filename = getStringUsingDataColumn ("_display_name", env, uri, contentResolver); + + // Fallback to "_data" column + if (filename.isEmpty()) + { + auto path = getStringUsingDataColumn ("_data", env, uri, contentResolver); + filename = path.fromLastOccurrenceOf ("/", false, true); + } + + return filename; + } + private: //============================================================================== static String getCursorDataColumn (const URL& url, const String& selection = {}, @@ -345,6 +367,42 @@ private: return LocalRef (getEnv()->CallStaticObjectMethod (AndroidUri, AndroidUri.parse, javaString (url.toString (true)).get())); } + + //============================================================================== + static String getStringUsingDataColumn (const String& columnNameToUse, JNIEnv* env, + const LocalRef& uri, + const LocalRef& contentResolver) + { + LocalRef columnName (javaString (columnNameToUse)); + LocalRef projection (env->NewObjectArray (1, JavaString, columnName.get())); + + LocalRef cursor (env->CallObjectMethod (contentResolver.get(), ContentResolver.query, + uri.get(), projection.get(), nullptr, + nullptr, nullptr)); + + if (cursor == 0) + return {}; + + String fileName; + + if (env->CallBooleanMethod (cursor.get(), AndroidCursor.moveToFirst) != 0) + { + auto columnIndex = env->CallIntMethod (cursor.get(), AndroidCursor.getColumnIndex, columnName.get()); + + if (columnIndex >= 0) + { + LocalRef value ((jstring) env->CallObjectMethod (cursor.get(), AndroidCursor.getString, columnIndex)); + + if (value) + fileName = juceString (value.get()); + + } + } + + env->CallVoidMethod (cursor.get(), AndroidCursor.close); + + return fileName; + } }; //============================================================================== diff --git a/modules/juce_core/native/juce_android_Network.cpp b/modules/juce_core/native/juce_android_Network.cpp index d1130bc1a3..0381837dd5 100644 --- a/modules/juce_core/native/juce_android_Network.cpp +++ b/modules/juce_core/native/juce_android_Network.cpp @@ -94,6 +94,14 @@ File URL::getLocalFile() const return fileFromFileSchemeURL (*this); } +String URL::getFileName() const +{ + if (getScheme() == "content") + return AndroidContentUriResolver::getFileNameFromContentUri (*this); + + return toString (false).fromLastOccurrenceOf ("/", false, true); +} + //============================================================================== class WebInputStream::Pimpl { diff --git a/modules/juce_core/network/juce_URL.cpp b/modules/juce_core/network/juce_URL.cpp index cc8e1485f0..27d5836ac7 100644 --- a/modules/juce_core/network/juce_URL.cpp +++ b/modules/juce_core/network/juce_URL.cpp @@ -359,6 +359,11 @@ File URL::getLocalFile() const { return fileFromFileSchemeURL (*this); } + +String URL::getFileName() const +{ + return toString (false).fromLastOccurrenceOf ("/", false, true); +} #endif File URL::fileFromFileSchemeURL (const URL& fileURL) diff --git a/modules/juce_core/network/juce_URL.h b/modules/juce_core/network/juce_URL.h index 4ff069a1ee..4ac1b856b1 100644 --- a/modules/juce_core/network/juce_URL.h +++ b/modules/juce_core/network/juce_URL.h @@ -111,6 +111,15 @@ public: */ File getLocalFile() const; + /** Returns the file name. For all but Android's content:// scheme, it will + simply return the last segment of the URL. + E.g. for "http://www.xyz.com/foo/bar.txt", this will return "bar.txt". + + For Android's content:// scheme, it will attempt to resolve the filename + located under the URL. + */ + String getFileName() const; + /** Attempts to read a port number from the URL. @returns the port number, or 0 if none is explicitly specified. */