mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-22 06:05:38 +00:00
(Android) Added preliminary support for copying assets to the internal data directory
This commit is contained in:
parent
27feef1b23
commit
a83763c2c3
|
@ -413,7 +413,7 @@ add_compile_definitions(GLM_FORCE_XYZW_ONLY)
|
||||||
|
|
||||||
# For Unix systems, assign the installation prefix. If it's not explicitly set,
|
# For Unix systems, assign the installation prefix. If it's not explicitly set,
|
||||||
# we use /usr on Linux, /usr/pkg on NetBSD and /usr/local on FreeBSD and OpenBSD.
|
# we use /usr on Linux, /usr/pkg on NetBSD and /usr/local on FreeBSD and OpenBSD.
|
||||||
if(NOT WIN32 AND NOT APPLE)
|
if(NOT WIN32 AND NOT APPLE AND NOT ANDROID)
|
||||||
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT)
|
||||||
if(CMAKE_SYSTEM_NAME MATCHES Linux)
|
if(CMAKE_SYSTEM_NAME MATCHES Linux)
|
||||||
set(CMAKE_INSTALL_PREFIX /usr CACHE INTERNAL CMAKE_INSTALL_PREFIX)
|
set(CMAKE_INSTALL_PREFIX /usr CACHE INTERNAL CMAKE_INSTALL_PREFIX)
|
||||||
|
|
|
@ -719,6 +719,10 @@ int main(int argc, char* argv[])
|
||||||
renderer = Renderer::getInstance();
|
renderer = Renderer::getInstance();
|
||||||
window = Window::getInstance();
|
window = Window::getInstance();
|
||||||
|
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
Utils::Platform::Android::setupResources();
|
||||||
|
#endif
|
||||||
|
|
||||||
ViewController::getInstance()->setMenuColors();
|
ViewController::getInstance()->setMenuColors();
|
||||||
CollectionSystemsManager::getInstance();
|
CollectionSystemsManager::getInstance();
|
||||||
Screensaver screensaver;
|
Screensaver screensaver;
|
||||||
|
|
|
@ -709,6 +709,8 @@ void ThemeData::populateThemes()
|
||||||
Utils::FileSystem::getExePath() + "/themes",
|
Utils::FileSystem::getExePath() + "/themes",
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
Utils::FileSystem::getExePath() + "/../Resources/themes",
|
Utils::FileSystem::getExePath() + "/../Resources/themes",
|
||||||
|
#elif defined(__ANDROID__)
|
||||||
|
ResourceManager::getInstance().getDataDirectory() + "/themes",
|
||||||
#elif defined(__unix__) && !defined(APPIMAGE_BUILD)
|
#elif defined(__unix__) && !defined(APPIMAGE_BUILD)
|
||||||
Utils::FileSystem::getProgramDataPath() + "/themes",
|
Utils::FileSystem::getProgramDataPath() + "/themes",
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -42,14 +42,17 @@ std::string ResourceManager::getResourcePath(const std::string& path, bool termi
|
||||||
return applePackagePath;
|
return applePackagePath;
|
||||||
}
|
}
|
||||||
#elif defined(__unix__) && !defined(APPIMAGE_BUILD)
|
#elif defined(__unix__) && !defined(APPIMAGE_BUILD)
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
std::string testDataPath {mDataDirectory + "/resources/" + &path[2]};
|
||||||
|
#else
|
||||||
// Check under the data installation directory (Unix only).
|
// Check under the data installation directory (Unix only).
|
||||||
std::string testDataPath {Utils::FileSystem::getProgramDataPath() + "/resources/" +
|
std::string testDataPath {Utils::FileSystem::getProgramDataPath() + "/resources/" +
|
||||||
&path[2]};
|
&path[2]};
|
||||||
|
|
||||||
if (Utils::FileSystem::exists(testDataPath)) {
|
|
||||||
return testDataPath;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
if (Utils::FileSystem::exists(testDataPath))
|
||||||
|
return testDataPath;
|
||||||
|
#endif
|
||||||
|
#if !defined(__ANDROID__)
|
||||||
// Check under the ES executable directory.
|
// Check under the ES executable directory.
|
||||||
std::string testExePath {Utils::FileSystem::getExePath() + "/resources/" + &path[2]};
|
std::string testExePath {Utils::FileSystem::getExePath() + "/resources/" + &path[2]};
|
||||||
|
|
||||||
|
@ -60,6 +63,14 @@ std::string ResourceManager::getResourcePath(const std::string& path, bool termi
|
||||||
// indicate that we have a broken EmulationStation installation. If the argument
|
// indicate that we have a broken EmulationStation installation. If the argument
|
||||||
// terminateOnFailure is set to false though, then skip this step.
|
// terminateOnFailure is set to false though, then skip this step.
|
||||||
else {
|
else {
|
||||||
|
#else
|
||||||
|
SDL_RWops* resFile {SDL_RWFromFile(path.substr(2).c_str(), "rb")};
|
||||||
|
if (resFile != nullptr) {
|
||||||
|
SDL_RWclose(resFile);
|
||||||
|
return path.substr(2);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
#endif
|
||||||
if (terminateOnFailure) {
|
if (terminateOnFailure) {
|
||||||
LOG(LogError) << "Program resource missing: " << path;
|
LOG(LogError) << "Program resource missing: " << path;
|
||||||
LOG(LogError) << "Tried to find the resource in the following locations:";
|
LOG(LogError) << "Tried to find the resource in the following locations:";
|
||||||
|
@ -69,7 +80,9 @@ std::string ResourceManager::getResourcePath(const std::string& path, bool termi
|
||||||
#elif defined(__unix__) && !defined(APPIMAGE_BUILD)
|
#elif defined(__unix__) && !defined(APPIMAGE_BUILD)
|
||||||
LOG(LogError) << testDataPath;
|
LOG(LogError) << testDataPath;
|
||||||
#endif
|
#endif
|
||||||
|
#if !defined(__ANDROID__)
|
||||||
LOG(LogError) << testExePath;
|
LOG(LogError) << testExePath;
|
||||||
|
#endif
|
||||||
LOG(LogError) << "Has EmulationStation been properly installed?";
|
LOG(LogError) << "Has EmulationStation been properly installed?";
|
||||||
Utils::Platform::emergencyShutdown();
|
Utils::Platform::emergencyShutdown();
|
||||||
}
|
}
|
||||||
|
@ -88,10 +101,19 @@ const ResourceData ResourceManager::getFileData(const std::string& path) const
|
||||||
// Check if its a resource.
|
// Check if its a resource.
|
||||||
const std::string respath {getResourcePath(path)};
|
const std::string respath {getResourcePath(path)};
|
||||||
|
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
SDL_RWops* resFile {SDL_RWFromFile(respath.c_str(), "rb")};
|
||||||
|
if (resFile != nullptr) {
|
||||||
|
ResourceData data {loadFile(resFile)};
|
||||||
|
SDL_RWclose(resFile);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
#else
|
||||||
if (Utils::FileSystem::exists(respath)) {
|
if (Utils::FileSystem::exists(respath)) {
|
||||||
ResourceData data {loadFile(respath)};
|
ResourceData data {loadFile(respath)};
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// If the file doesn't exist, return an "empty" ResourceData.
|
// If the file doesn't exist, return an "empty" ResourceData.
|
||||||
ResourceData data {nullptr, 0};
|
ResourceData data {nullptr, 0};
|
||||||
|
@ -107,7 +129,7 @@ ResourceData ResourceManager::loadFile(const std::string& path) const
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
stream.seekg(0, stream.end);
|
stream.seekg(0, stream.end);
|
||||||
size_t size {static_cast<size_t>(stream.tellg())};
|
const size_t size {static_cast<size_t>(stream.tellg())};
|
||||||
stream.seekg(0, stream.beg);
|
stream.seekg(0, stream.beg);
|
||||||
|
|
||||||
// Supply custom deleter to properly free array.
|
// Supply custom deleter to properly free array.
|
||||||
|
@ -120,6 +142,17 @@ ResourceData ResourceManager::loadFile(const std::string& path) const
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ResourceData ResourceManager::loadFile(SDL_RWops* resFile) const
|
||||||
|
{
|
||||||
|
const size_t size {static_cast<size_t>(SDL_RWsize(resFile))};
|
||||||
|
std::shared_ptr<unsigned char> data {new unsigned char[size],
|
||||||
|
[](unsigned char* p) { delete[] p; }};
|
||||||
|
SDL_RWread(resFile, reinterpret_cast<char*>(data.get()), 1, size);
|
||||||
|
|
||||||
|
ResourceData ret {data, size};
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
bool ResourceManager::fileExists(const std::string& path) const
|
bool ResourceManager::fileExists(const std::string& path) const
|
||||||
{
|
{
|
||||||
// If it exists as a resource file, return true.
|
// If it exists as a resource file, return true.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
//
|
//
|
||||||
// EmulationStation Desktop Edition
|
// ES-DE
|
||||||
// ResourceManager.h
|
// ResourceManager.h
|
||||||
//
|
//
|
||||||
// Handles the application resources (fonts, graphics, sounds etc.).
|
// Handles the application resources (fonts, graphics, sounds etc.).
|
||||||
|
@ -14,6 +14,8 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <SDL2/SDL_rwops.h>
|
||||||
|
|
||||||
// The ResourceManager exists to:
|
// The ResourceManager exists to:
|
||||||
// Allow loading resources embedded into the executable like an actual file.
|
// Allow loading resources embedded into the executable like an actual file.
|
||||||
// Allow embedded resources to be optionally remapped to actual files for further customization.
|
// Allow embedded resources to be optionally remapped to actual files for further customization.
|
||||||
|
@ -42,6 +44,9 @@ public:
|
||||||
void unloadAll();
|
void unloadAll();
|
||||||
void reloadAll();
|
void reloadAll();
|
||||||
|
|
||||||
|
void setDataDirectory(const std::string& dataDirectory) { mDataDirectory = dataDirectory; }
|
||||||
|
const std::string& getDataDirectory() const { return mDataDirectory; }
|
||||||
|
|
||||||
std::string getResourcePath(const std::string& path, bool terminateOnFailure = true) const;
|
std::string getResourcePath(const std::string& path, bool terminateOnFailure = true) const;
|
||||||
const ResourceData getFileData(const std::string& path) const;
|
const ResourceData getFileData(const std::string& path) const;
|
||||||
bool fileExists(const std::string& path) const;
|
bool fileExists(const std::string& path) const;
|
||||||
|
@ -49,9 +54,11 @@ public:
|
||||||
private:
|
private:
|
||||||
ResourceManager() noexcept {}
|
ResourceManager() noexcept {}
|
||||||
|
|
||||||
std::list<std::weak_ptr<IReloadable>> mReloadables;
|
|
||||||
|
|
||||||
ResourceData loadFile(const std::string& path) const;
|
ResourceData loadFile(const std::string& path) const;
|
||||||
|
ResourceData loadFile(SDL_RWops* resFile) const;
|
||||||
|
|
||||||
|
std::list<std::weak_ptr<IReloadable>> mReloadables;
|
||||||
|
std::string mDataDirectory;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // ES_CORE_RESOURCES_RESOURCE_MANAGER_H
|
#endif // ES_CORE_RESOURCES_RESOURCE_MANAGER_H
|
||||||
|
|
|
@ -387,13 +387,53 @@ namespace Utils
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool setupResources()
|
||||||
|
{
|
||||||
|
JNIEnv* jniEnv {reinterpret_cast<JNIEnv*>(SDL_AndroidGetJNIEnv())};
|
||||||
|
{
|
||||||
|
jclass jniClass {jniEnv->FindClass("org/es_de/frontend/MainActivity")};
|
||||||
|
jmethodID methodID {jniEnv->GetStaticMethodID(jniClass, "getDataDirectory",
|
||||||
|
"()Ljava/lang/String;")};
|
||||||
|
jstring dataDirectory {
|
||||||
|
static_cast<jstring>(jniEnv->CallStaticObjectMethod(jniClass, methodID))};
|
||||||
|
const char* dataDirUtf {jniEnv->GetStringUTFChars(dataDirectory, nullptr)};
|
||||||
|
ResourceManager::getInstance().setDataDirectory(std::string(dataDirUtf));
|
||||||
|
jniEnv->ReleaseStringUTFChars(dataDirectory, dataDirUtf);
|
||||||
|
jniEnv->DeleteLocalRef(jniClass);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
jclass jniClass {jniEnv->FindClass("org/es_de/frontend/MainActivity")};
|
||||||
|
jmethodID methodID {
|
||||||
|
jniEnv->GetStaticMethodID(jniClass, "setupResources", "()Z")};
|
||||||
|
const bool returnValue {
|
||||||
|
static_cast<bool>(jniEnv->CallStaticBooleanMethod(jniClass, methodID))};
|
||||||
|
jniEnv->DeleteLocalRef(jniClass);
|
||||||
|
if (returnValue) {
|
||||||
|
LOG(LogError) << "Couldn't setup application resources on internal storage";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
jclass jniClass {jniEnv->FindClass("org/es_de/frontend/MainActivity")};
|
||||||
|
jmethodID methodID {jniEnv->GetStaticMethodID(jniClass, "setupThemes", "()Z")};
|
||||||
|
const bool returnValue {
|
||||||
|
static_cast<bool>(jniEnv->CallStaticBooleanMethod(jniClass, methodID))};
|
||||||
|
jniEnv->DeleteLocalRef(jniClass);
|
||||||
|
if (returnValue) {
|
||||||
|
LOG(LogError) << "Couldn't setup application themes on internal storage";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool checkEmulatorInstalled(const std::string& packageName, const std::string& activity)
|
bool checkEmulatorInstalled(const std::string& packageName, const std::string& activity)
|
||||||
{
|
{
|
||||||
JNIEnv* jniEnv {reinterpret_cast<JNIEnv*>(SDL_AndroidGetJNIEnv())};
|
JNIEnv* jniEnv {reinterpret_cast<JNIEnv*>(SDL_AndroidGetJNIEnv())};
|
||||||
jclass jniClass {jniEnv->FindClass("org/es_de/frontend/MainActivity")};
|
jclass jniClass {jniEnv->FindClass("org/es_de/frontend/MainActivity")};
|
||||||
jmethodID methodID {jniEnv->GetStaticMethodID(
|
jmethodID methodID {jniEnv->GetStaticMethodID(
|
||||||
jniClass, "checkEmulatorInstalled", "(Ljava/lang/String;Ljava/lang/String;)Z")};
|
jniClass, "checkEmulatorInstalled", "(Ljava/lang/String;Ljava/lang/String;)Z")};
|
||||||
bool returnValue {static_cast<bool>(jniEnv->CallStaticBooleanMethod(
|
const bool returnValue {static_cast<bool>(jniEnv->CallStaticBooleanMethod(
|
||||||
jniClass, methodID, jniEnv->NewStringUTF(packageName.c_str()),
|
jniClass, methodID, jniEnv->NewStringUTF(packageName.c_str()),
|
||||||
jniEnv->NewStringUTF(activity.c_str())))};
|
jniEnv->NewStringUTF(activity.c_str())))};
|
||||||
// jniEnv->DeleteLocalRef(jniClass);
|
// jniEnv->DeleteLocalRef(jniClass);
|
||||||
|
|
|
@ -60,6 +60,7 @@ namespace Utils
|
||||||
namespace Android
|
namespace Android
|
||||||
{
|
{
|
||||||
bool requestStoragePermission();
|
bool requestStoragePermission();
|
||||||
|
bool setupResources();
|
||||||
bool checkEmulatorInstalled(const std::string& packageName,
|
bool checkEmulatorInstalled(const std::string& packageName,
|
||||||
const std::string& activity);
|
const std::string& activity);
|
||||||
int launchGame(const std::string& packageName,
|
int launchGame(const std::string& packageName,
|
||||||
|
|
Loading…
Reference in a new issue