Android: Add content provider support to File::IOFile
Taking the hit now to prepare us for when Google Play will force us to use scoped storage...
This commit is contained in:
parent
d9f3e382fe
commit
6e1e6d2311
|
@ -0,0 +1,23 @@
|
|||
package org.dolphinemu.dolphinemu.utils;
|
||||
|
||||
import android.net.Uri;
|
||||
|
||||
import org.dolphinemu.dolphinemu.DolphinApplication;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
|
||||
public class ContentHandler
|
||||
{
|
||||
public static int openFd(String uri, String mode)
|
||||
{
|
||||
try
|
||||
{
|
||||
return DolphinApplication.getAppContext().getContentResolver()
|
||||
.openFileDescriptor(Uri.parse(uri), mode).detachFd();
|
||||
}
|
||||
catch (FileNotFoundException | NullPointerException e)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@
|
|||
#include <jni.h>
|
||||
|
||||
#include "Common/StringUtil.h"
|
||||
#include "jni/AndroidCommon/IDCache.h"
|
||||
|
||||
std::string GetJString(JNIEnv* env, jstring jstr)
|
||||
{
|
||||
|
@ -40,3 +41,20 @@ std::vector<std::string> JStringArrayToVector(JNIEnv* env, jobjectArray array)
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
int OpenAndroidContent(const std::string& uri, const std::string& mode)
|
||||
{
|
||||
JNIEnv* env = IDCache::GetEnvForThread();
|
||||
const jint fd = env->CallStaticIntMethod(IDCache::GetContentHandlerClass(),
|
||||
IDCache::GetContentHandlerOpenFd(), ToJString(env, uri),
|
||||
ToJString(env, mode));
|
||||
|
||||
// We can get an IllegalArgumentException when passing an invalid mode
|
||||
if (env->ExceptionCheck())
|
||||
{
|
||||
env->ExceptionDescribe();
|
||||
abort();
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
|
|
@ -11,3 +11,5 @@
|
|||
std::string GetJString(JNIEnv* env, jstring jstr);
|
||||
jstring ToJString(JNIEnv* env, const std::string& str);
|
||||
std::vector<std::string> JStringArrayToVector(JNIEnv* env, jobjectArray array);
|
||||
|
||||
int OpenAndroidContent(const std::string& uri, const std::string& mode);
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
add_library(androidcommon STATIC
|
||||
AndroidCommon.cpp
|
||||
AndroidCommon.h
|
||||
IDCache.cpp
|
||||
IDCache.h
|
||||
)
|
||||
|
||||
target_link_libraries(androidcommon
|
||||
PRIVATE
|
||||
android
|
||||
log
|
||||
"-Wl,--no-warn-mismatch"
|
||||
"-Wl,--whole-archive"
|
||||
"-Wl,--no-whole-archive"
|
||||
)
|
|
@ -39,6 +39,9 @@ static jmethodID s_ini_file_section_constructor;
|
|||
static jclass s_compress_cb_class;
|
||||
static jmethodID s_compress_cb_run;
|
||||
|
||||
static jclass s_content_handler_class;
|
||||
static jmethodID s_content_handler_open_fd;
|
||||
|
||||
namespace IDCache
|
||||
{
|
||||
JNIEnv* GetEnvForThread()
|
||||
|
@ -174,6 +177,16 @@ jmethodID GetCompressCallbackRun()
|
|||
return s_compress_cb_run;
|
||||
}
|
||||
|
||||
jclass GetContentHandlerClass()
|
||||
{
|
||||
return s_content_handler_class;
|
||||
}
|
||||
|
||||
jmethodID GetContentHandlerOpenFd()
|
||||
{
|
||||
return s_content_handler_open_fd;
|
||||
}
|
||||
|
||||
} // namespace IDCache
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -241,6 +254,12 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved)
|
|||
s_compress_cb_class = reinterpret_cast<jclass>(env->NewGlobalRef(compress_cb_class));
|
||||
s_compress_cb_run = env->GetMethodID(s_compress_cb_class, "run", "(Ljava/lang/String;F)Z");
|
||||
|
||||
const jclass content_handler_class =
|
||||
env->FindClass("org/dolphinemu/dolphinemu/utils/ContentHandler");
|
||||
s_content_handler_class = reinterpret_cast<jclass>(env->NewGlobalRef(content_handler_class));
|
||||
s_content_handler_open_fd = env->GetStaticMethodID(s_content_handler_class, "openFd",
|
||||
"(Ljava/lang/String;Ljava/lang/String;)I");
|
||||
|
||||
return JNI_VERSION;
|
||||
}
|
||||
|
||||
|
@ -258,6 +277,7 @@ void JNI_OnUnload(JavaVM* vm, void* reserved)
|
|||
env->DeleteGlobalRef(s_ini_file_class);
|
||||
env->DeleteGlobalRef(s_ini_file_section_class);
|
||||
env->DeleteGlobalRef(s_compress_cb_class);
|
||||
env->DeleteGlobalRef(s_content_handler_class);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -41,4 +41,7 @@ jmethodID GetIniFileSectionConstructor();
|
|||
jclass GetCompressCallbackClass();
|
||||
jmethodID GetCompressCallbackRun();
|
||||
|
||||
jclass GetContentHandlerClass();
|
||||
jmethodID GetContentHandlerOpenFd();
|
||||
|
||||
} // namespace IDCache
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
add_library(main SHARED
|
||||
AndroidCommon/AndroidCommon.cpp
|
||||
AndroidCommon/IDCache.cpp
|
||||
GameList/GameFile.cpp
|
||||
GameList/GameFile.h
|
||||
GameList/GameFileCache.cpp
|
||||
IniFile.cpp
|
||||
MainAndroid.cpp
|
||||
|
@ -10,6 +9,7 @@ add_library(main SHARED
|
|||
|
||||
target_link_libraries(main
|
||||
PRIVATE
|
||||
androidcommon
|
||||
core
|
||||
uicommon
|
||||
)
|
||||
|
@ -32,3 +32,5 @@ file(REMOVE_RECURSE ${CMAKE_SOURCE_DIR}/Source/Android/app/src/main/assets/Sys/R
|
|||
file(REMOVE_RECURSE ${CMAKE_SOURCE_DIR}/Source/Android/app/src/main/assets/Sys/Themes/)
|
||||
|
||||
set(CPACK_PACKAGE_EXECUTABLES ${CPACK_PACKAGE_EXECUTABLES} main)
|
||||
|
||||
add_subdirectory(AndroidCommon)
|
||||
|
|
|
@ -64,8 +64,8 @@ if (MSVC)
|
|||
add_definitions(/I${PCH_DIRECTORY})
|
||||
add_definitions(/Yu${PCH_PATH})
|
||||
|
||||
# Don't include timestamps in binaries
|
||||
add_link_options(/Brepro)
|
||||
# Don't include timestamps in binaries
|
||||
add_link_options(/Brepro)
|
||||
endif()
|
||||
|
||||
# These aren't actually needed for C11/C++11
|
||||
|
|
|
@ -164,6 +164,11 @@ elseif(WIN32)
|
|||
if (_M_X86_64)
|
||||
target_link_libraries(common PRIVATE opengl32.lib)
|
||||
endif()
|
||||
elseif (ANDROID)
|
||||
target_link_libraries(common
|
||||
PRIVATE
|
||||
androidcommon
|
||||
)
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
|
|
|
@ -15,6 +15,13 @@
|
|||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <algorithm>
|
||||
|
||||
#include "Common/StringUtil.h"
|
||||
#include "jni/AndroidCommon/AndroidCommon.h"
|
||||
#endif
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/File.h"
|
||||
#include "Common/FileUtil.h"
|
||||
|
@ -62,7 +69,21 @@ bool IOFile::Open(const std::string& filename, const char openmode[])
|
|||
#ifdef _WIN32
|
||||
m_good = _tfopen_s(&m_file, UTF8ToTStr(filename).c_str(), UTF8ToTStr(openmode).c_str()) == 0;
|
||||
#else
|
||||
m_file = std::fopen(filename.c_str(), openmode);
|
||||
#ifdef ANDROID
|
||||
if (StringBeginsWith(filename, "content://"))
|
||||
{
|
||||
// The Java method which OpenAndroidContent passes the mode to does not support the b specifier.
|
||||
// Since we're on POSIX, it's fine to just remove the b.
|
||||
std::string mode_without_b(openmode);
|
||||
mode_without_b.erase(std::remove(mode_without_b.begin(), mode_without_b.end(), 'b'),
|
||||
mode_without_b.end());
|
||||
m_file = fdopen(OpenAndroidContent(filename, mode_without_b), mode_without_b.c_str());
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
m_file = std::fopen(filename.c_str(), openmode);
|
||||
}
|
||||
m_good = m_file != nullptr;
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in New Issue