mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-09 23:59:27 +01:00
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 <jni.h>
|
||||||
|
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
|
#include "jni/AndroidCommon/IDCache.h"
|
||||||
|
|
||||||
std::string GetJString(JNIEnv* env, jstring jstr)
|
std::string GetJString(JNIEnv* env, jstring jstr)
|
||||||
{
|
{
|
||||||
@ -40,3 +41,20 @@ std::vector<std::string> JStringArrayToVector(JNIEnv* env, jobjectArray array)
|
|||||||
|
|
||||||
return result;
|
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);
|
std::string GetJString(JNIEnv* env, jstring jstr);
|
||||||
jstring ToJString(JNIEnv* env, const std::string& str);
|
jstring ToJString(JNIEnv* env, const std::string& str);
|
||||||
std::vector<std::string> JStringArrayToVector(JNIEnv* env, jobjectArray array);
|
std::vector<std::string> JStringArrayToVector(JNIEnv* env, jobjectArray array);
|
||||||
|
|
||||||
|
int OpenAndroidContent(const std::string& uri, const std::string& mode);
|
||||||
|
15
Source/Android/jni/AndroidCommon/CMakeLists.txt
Normal file
15
Source/Android/jni/AndroidCommon/CMakeLists.txt
Normal file
@ -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 jclass s_compress_cb_class;
|
||||||
static jmethodID s_compress_cb_run;
|
static jmethodID s_compress_cb_run;
|
||||||
|
|
||||||
|
static jclass s_content_handler_class;
|
||||||
|
static jmethodID s_content_handler_open_fd;
|
||||||
|
|
||||||
namespace IDCache
|
namespace IDCache
|
||||||
{
|
{
|
||||||
JNIEnv* GetEnvForThread()
|
JNIEnv* GetEnvForThread()
|
||||||
@ -174,6 +177,16 @@ jmethodID GetCompressCallbackRun()
|
|||||||
return s_compress_cb_run;
|
return s_compress_cb_run;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
jclass GetContentHandlerClass()
|
||||||
|
{
|
||||||
|
return s_content_handler_class;
|
||||||
|
}
|
||||||
|
|
||||||
|
jmethodID GetContentHandlerOpenFd()
|
||||||
|
{
|
||||||
|
return s_content_handler_open_fd;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace IDCache
|
} // namespace IDCache
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#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_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");
|
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;
|
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_class);
|
||||||
env->DeleteGlobalRef(s_ini_file_section_class);
|
env->DeleteGlobalRef(s_ini_file_section_class);
|
||||||
env->DeleteGlobalRef(s_compress_cb_class);
|
env->DeleteGlobalRef(s_compress_cb_class);
|
||||||
|
env->DeleteGlobalRef(s_content_handler_class);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -41,4 +41,7 @@ jmethodID GetIniFileSectionConstructor();
|
|||||||
jclass GetCompressCallbackClass();
|
jclass GetCompressCallbackClass();
|
||||||
jmethodID GetCompressCallbackRun();
|
jmethodID GetCompressCallbackRun();
|
||||||
|
|
||||||
|
jclass GetContentHandlerClass();
|
||||||
|
jmethodID GetContentHandlerOpenFd();
|
||||||
|
|
||||||
} // namespace IDCache
|
} // namespace IDCache
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
add_library(main SHARED
|
add_library(main SHARED
|
||||||
AndroidCommon/AndroidCommon.cpp
|
|
||||||
AndroidCommon/IDCache.cpp
|
|
||||||
GameList/GameFile.cpp
|
GameList/GameFile.cpp
|
||||||
|
GameList/GameFile.h
|
||||||
GameList/GameFileCache.cpp
|
GameList/GameFileCache.cpp
|
||||||
IniFile.cpp
|
IniFile.cpp
|
||||||
MainAndroid.cpp
|
MainAndroid.cpp
|
||||||
@ -10,6 +9,7 @@ add_library(main SHARED
|
|||||||
|
|
||||||
target_link_libraries(main
|
target_link_libraries(main
|
||||||
PRIVATE
|
PRIVATE
|
||||||
|
androidcommon
|
||||||
core
|
core
|
||||||
uicommon
|
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/)
|
file(REMOVE_RECURSE ${CMAKE_SOURCE_DIR}/Source/Android/app/src/main/assets/Sys/Themes/)
|
||||||
|
|
||||||
set(CPACK_PACKAGE_EXECUTABLES ${CPACK_PACKAGE_EXECUTABLES} main)
|
set(CPACK_PACKAGE_EXECUTABLES ${CPACK_PACKAGE_EXECUTABLES} main)
|
||||||
|
|
||||||
|
add_subdirectory(AndroidCommon)
|
||||||
|
@ -64,8 +64,8 @@ if (MSVC)
|
|||||||
add_definitions(/I${PCH_DIRECTORY})
|
add_definitions(/I${PCH_DIRECTORY})
|
||||||
add_definitions(/Yu${PCH_PATH})
|
add_definitions(/Yu${PCH_PATH})
|
||||||
|
|
||||||
# Don't include timestamps in binaries
|
# Don't include timestamps in binaries
|
||||||
add_link_options(/Brepro)
|
add_link_options(/Brepro)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# These aren't actually needed for C11/C++11
|
# These aren't actually needed for C11/C++11
|
||||||
|
@ -164,6 +164,11 @@ elseif(WIN32)
|
|||||||
if (_M_X86_64)
|
if (_M_X86_64)
|
||||||
target_link_libraries(common PRIVATE opengl32.lib)
|
target_link_libraries(common PRIVATE opengl32.lib)
|
||||||
endif()
|
endif()
|
||||||
|
elseif (ANDROID)
|
||||||
|
target_link_libraries(common
|
||||||
|
PRIVATE
|
||||||
|
androidcommon
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(ANDROID)
|
if(ANDROID)
|
||||||
|
@ -15,6 +15,13 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef ANDROID
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "Common/StringUtil.h"
|
||||||
|
#include "jni/AndroidCommon/AndroidCommon.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/File.h"
|
#include "Common/File.h"
|
||||||
#include "Common/FileUtil.h"
|
#include "Common/FileUtil.h"
|
||||||
@ -62,7 +69,21 @@ bool IOFile::Open(const std::string& filename, const char openmode[])
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
m_good = _tfopen_s(&m_file, UTF8ToTStr(filename).c_str(), UTF8ToTStr(openmode).c_str()) == 0;
|
m_good = _tfopen_s(&m_file, UTF8ToTStr(filename).c_str(), UTF8ToTStr(openmode).c_str()) == 0;
|
||||||
#else
|
#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;
|
m_good = m_file != nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user