From 310fb6e809878c13ac9525717718fdf3da2d5201 Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Sun, 26 Nov 2023 13:32:11 +0100 Subject: [PATCH] (Android) Added find rules logic and launch command configuration logic Also did some general refactoring of the emulator launch code --- es-app/src/FileData.cpp | 257 +++++++++++++++++++++-------- es-app/src/FileData.h | 10 +- es-app/src/SystemData.cpp | 14 +- es-app/src/SystemData.h | 2 + es-core/src/utils/PlatformUtil.cpp | 51 +++++- es-core/src/utils/PlatformUtil.h | 7 +- 6 files changed, 268 insertions(+), 73 deletions(-) diff --git a/es-app/src/FileData.cpp b/es-app/src/FileData.cpp index 69eb22899..52153ae9a 100644 --- a/es-app/src/FileData.cpp +++ b/es-app/src/FileData.cpp @@ -947,6 +947,12 @@ void FileData::launchGame() bool foundCoreFile {false}; std::vector emulatorCorePaths; +#if defined(__ANDROID__) + std::string androidPackage; + std::string androidComponent; + std::vector> androidExtras; +#endif + #if defined(_WIN64) bool hideWindow {false}; @@ -997,30 +1003,27 @@ void FileData::launchGame() // Expand home path if ~ is used. command = Utils::FileSystem::expandHomePath(command); - std::string preCommandPath; - // Check for any pre-command entry, and if it exists then expand it using the find rules. if (command.find("%PRECOMMAND_") != std::string::npos) { - preCommandPath = findEmulatorPath(command, true); + const std::pair preCommand { + findEmulator(command, true)}; // Show an error message if there was no matching emulator entry in es_find_rules.xml. - if (preCommandPath.substr(0, 18) == "NO EMULATOR RULE: ") { - const std::string& preCommandEntry { - preCommandPath.substr(18, preCommandPath.size() - 18)}; + if (preCommand.second == FileData::findEmulatorResult::NO_RULES) { LOG(LogError) << "Couldn't launch game, either there is no emulator entry for pre-command \"" - << preCommandEntry << "\" in es_find_rules.xml or there are no rules defined"; + << preCommand.first << "\" in es_find_rules.xml or there are no rules defined"; LOG(LogError) << "Raw emulator launch command:"; LOG(LogError) << commandRaw; window->queueInfoPopup("ERROR: MISSING PRE-COMMAND FIND RULES CONFIGURATION FOR '" + - preCommandEntry + "'", + preCommand.first + "'", 6000); window->setAllowTextScrolling(true); window->setAllowFileAnimation(true); return; } - else if (preCommandPath.empty()) { - LOG(LogError) << "Couldn't launch game, pre-command binary not found"; + else if (preCommand.first.empty()) { + LOG(LogError) << "Couldn't launch game, pre-command not found"; LOG(LogError) << "Raw emulator launch command:"; LOG(LogError) << commandRaw; @@ -1047,30 +1050,30 @@ void FileData::launchGame() return; } else { - LOG(LogDebug) << "FileData::launchGame(): Pre-command binary set to \"" - << preCommandPath << "\""; + LOG(LogDebug) << "FileData::launchGame(): Pre-command set to \"" << preCommand.first + << "\""; } } - // Check that the emulator binary actually exists, and if so, get its path. - const std::string& binaryPath {findEmulatorPath(command, false)}; + // Check that the emulator actually exists, and if so, get its path. + const std::pair emulator { + findEmulator(command, false)}; // Show an error message if there was no matching emulator entry in es_find_rules.xml. - if (binaryPath.substr(0, 18) == "NO EMULATOR RULE: ") { - const std::string& emulatorEntry {binaryPath.substr(18, binaryPath.size() - 18)}; + if (emulator.second == FileData::findEmulatorResult::NO_RULES) { LOG(LogError) << "Couldn't launch game, either there is no emulator entry for \"" - << emulatorEntry << "\" in es_find_rules.xml or there are no rules defined"; + << emulator.first << "\" in es_find_rules.xml or there are no rules defined"; LOG(LogError) << "Raw emulator launch command:"; LOG(LogError) << commandRaw; window->queueInfoPopup( - "ERROR: MISSING EMULATOR FIND RULES CONFIGURATION FOR '" + emulatorEntry + "'", 6000); + "ERROR: MISSING EMULATOR FIND RULES CONFIGURATION FOR '" + emulator.first + "'", 6000); window->setAllowTextScrolling(true); window->setAllowFileAnimation(true); return; } - else if (binaryPath.empty()) { - LOG(LogError) << "Couldn't launch game, emulator binary not found"; + else if (emulator.second == FileData::findEmulatorResult::NOT_FOUND) { + LOG(LogError) << "Couldn't launch game, emulator not found"; LOG(LogError) << "Raw emulator launch command:"; LOG(LogError) << commandRaw; @@ -1098,15 +1101,27 @@ void FileData::launchGame() } #if defined(_WIN64) else { - std::string binaryLogPath {Utils::String::replace( - Utils::String::replace(binaryPath, "%ESPATH%", esPath), "/", "\\")}; - if (binaryLogPath.front() != '\"' && binaryLogPath.back() != '\"') - binaryLogPath = "\"" + binaryLogPath + "\""; - LOG(LogDebug) << "FileData::launchGame(): Emulator binary set to " << binaryLogPath; + std::string emulatorLogPath {Utils::String::replace( + Utils::String::replace(emulator.first, "%ESPATH%", esPath), "/", "\\")}; + if (emulatorLogPath.front() != '\"' && emulatorLogPath.back() != '\"') + emulatorLogPath = "\"" + emulatorLogPath + "\""; + LOG(LogDebug) << "FileData::launchGame(): Emulator set to " << emulatorLogPath; #else +#if defined(__ANDROID__) + else if (emulator.second == FileData::findEmulatorResult::FOUND_ANDROID_PACKAGE) { + androidPackage = emulator.first; + const size_t pipePos {androidPackage.find('|')}; + if (pipePos != std::string::npos) { + androidComponent = androidPackage.substr(pipePos + 1); + androidPackage = androidPackage.substr(0, pipePos); + } + LOG(LogDebug) << "FileData::launchGame(): Found Android emulator package \"" + << androidPackage << "\""; + } +#endif else if (!isShortcut) { - LOG(LogDebug) << "FileData::launchGame(): Emulator binary set to \"" - << Utils::String::replace(binaryPath, "%ESPATH%", esPath) << "\""; + LOG(LogDebug) << "FileData::launchGame(): Emulator set to \"" + << Utils::String::replace(emulator.first, "%ESPATH%", esPath) << "\""; #endif } @@ -1127,11 +1142,12 @@ void FileData::launchGame() if (spacePos != std::string::npos) { coreRaw = command.substr(emuPathPos, spacePos - emuPathPos); #if defined(_WIN64) - coreFile = Utils::FileSystem::getParent(Utils::String::replace(binaryPath, "\"", "")) + - command.substr(emuPathPos + 9, spacePos - emuPathPos - 9); + coreFile = + Utils::FileSystem::getParent(Utils::String::replace(emulator.first, "\"", "")) + + command.substr(emuPathPos + 9, spacePos - emuPathPos - 9); coreFile = Utils::String::replace(coreFile, "/", "\\"); #else - coreFile = Utils::FileSystem::getParent(binaryPath) + + coreFile = Utils::FileSystem::getParent(emulator.first) + command.substr(emuPathPos + 9, spacePos - emuPathPos - 9); #endif if (hasQuotationMark) { @@ -1192,7 +1208,7 @@ void FileData::launchGame() // the emulator core using the rules defined in es_find_rules.xml. for (std::string& path : emulatorCorePaths) { // The position of the %CORE_ variable could have changed as there may have been an - // %EMULATOR_ variable that was substituted for the actual emulator binary. + // %EMULATOR_ variable that was substituted for the actual emulator. coreEntryPos = command.find("%CORE_"); coreFilePos = command.find("%", coreEntryPos + 6); @@ -1218,10 +1234,11 @@ void FileData::launchGame() #if defined(_WIN64) coreFile = coreFile.replace( stringPos, 9, - Utils::FileSystem::getParent(Utils::String::replace(binaryPath, "\"", ""))); + Utils::FileSystem::getParent(Utils::String::replace(emulator.first, "\"", ""))); coreFile = Utils::String::replace(coreFile, "/", "\\"); #else - coreFile = coreFile.replace(stringPos, 9, Utils::FileSystem::getParent(binaryPath)); + coreFile = + coreFile.replace(stringPos, 9, Utils::FileSystem::getParent(emulator.first)); #endif } @@ -1325,7 +1342,7 @@ void FileData::launchGame() #if defined(_WIN64) startDirectory = Utils::String::replace( startDirectory, "%EMUDIR%", - Utils::FileSystem::getParent(Utils::String::replace(binaryPath, "\"", ""))); + Utils::FileSystem::getParent(Utils::String::replace(emulator.first, "\"", ""))); startDirectory = Utils::String::replace( startDirectory, "%GAMEDIR%", @@ -1336,7 +1353,7 @@ void FileData::launchGame() #else startDirectory = Utils::String::replace( startDirectory, "%EMUDIR%", - Utils::FileSystem::getParent(Utils::String::replace(binaryPath, "\\", ""))); + Utils::FileSystem::getParent(Utils::String::replace(emulator.first, "\\", ""))); startDirectory = Utils::String::replace( startDirectory, "%GAMEDIR%", @@ -1500,7 +1517,7 @@ void FileData::launchGame() if (Utils::FileSystem::exists(Utils::String::replace(romPath, "\\", ""))) { LOG(LogInfo) << "Opening app or alias file \"" << Utils::String::replace(romPath, "\\", "") << "\""; - command = Utils::String::replace(command, binaryPath, "open -W -a"); + command = Utils::String::replace(command, emulator.first, "open -W -a"); } else { LOG(LogError) << "App or alias file \"" << romPath @@ -1551,7 +1568,7 @@ void FileData::launchGame() } romPath = Utils::String::replace(romPath, "%%", "%"); romPath = Utils::String::trim(romPath); - command = Utils::String::replace(command, binaryPath, ""); + command = Utils::String::replace(command, emulator.first, ""); execEntry = true; break; } @@ -1583,12 +1600,71 @@ void FileData::launchGame() command = Utils::String::replace(command, "%ROMRAW%", romRaw); command = Utils::String::replace(command, "%ROMPATH%", Utils::FileSystem::getEscapedPath(getROMDirectory())); +#if defined(__ANDROID__) + command = Utils::String::replace(command, "%ANDROIDPACKAGE%", androidPackage); + size_t extraPos {command.find("%EXTRA_")}; + + while (extraPos != std::string::npos) { + if (extraPos != std::string::npos) { + bool invalidEntry {false}; + bool isQuoted {false}; + std::string extraName; + std::string extraValue; + + size_t equalPos {command.find("=", extraPos)}; + if (equalPos == std::string::npos) + invalidEntry = true; + + if (!invalidEntry && extraPos + 8 >= command.size()) + invalidEntry = true; + + if (!invalidEntry) { + if (command.length() > equalPos && command[equalPos + 1] == '\"') + isQuoted = true; + + extraName = command.substr(extraPos + 7, equalPos - (extraPos + 8)); + + if (isQuoted) { + const size_t closeQuotePos {command.find("\"", equalPos + 2)}; + if (closeQuotePos != std::string::npos) + extraValue = command.substr(equalPos + 2, closeQuotePos - (equalPos + 2)); + else + invalidEntry = true; + } + else { + const size_t spacePos {command.find(" ", extraPos)}; + if (spacePos != std::string::npos) + extraValue = command.substr(equalPos + 1, spacePos - (equalPos + 1)); + else + extraValue = command.substr(equalPos + 1, command.size() - equalPos); + } + + if (invalidEntry) { + LOG(LogError) << "Invalid entry in systems configuration file es_systems.xml"; + LOG(LogError) << "Raw emulator launch command:"; + LOG(LogError) << commandRaw; + + window->queueInfoPopup("ERROR: INVALID ENTRY IN SYSTEMS CONFIGURATION FILE", + 6000); + window->setAllowTextScrolling(true); + window->setAllowFileAnimation(true); + return; + } + + if (extraName != "" && extraValue != "") + androidExtras.emplace_back(make_pair(extraName, extraValue)); + } + } + extraPos = command.find("%EXTRA_", extraPos + 1); + } +#endif + #if defined(_WIN64) command = Utils::String::replace( command, "%ESPATH%", Utils::String::replace(Utils::FileSystem::getExePath(), "/", "\\")); command = Utils::String::replace(command, "%EMUDIR%", Utils::FileSystem::getEscapedPath(Utils::FileSystem::getParent( - Utils::String::replace(binaryPath, "\"", "")))); + Utils::String::replace(emulator.first, "\"", "")))); command = Utils::String::replace(command, "%GAMEDIR%", Utils::FileSystem::getEscapedPath(Utils::FileSystem::getParent( Utils::String::replace(romPath, "\"", "")))); @@ -1600,7 +1676,7 @@ void FileData::launchGame() command = Utils::String::replace(command, "%ESPATH%", Utils::FileSystem::getExePath()); command = Utils::String::replace(command, "%EMUDIR%", Utils::FileSystem::getEscapedPath(Utils::FileSystem::getParent( - Utils::String::replace(binaryPath, "\\", "")))); + Utils::String::replace(emulator.first, "\\", "")))); command = Utils::String::replace(command, "%GAMEDIR%", Utils::FileSystem::getEscapedPath(Utils::FileSystem::getParent( Utils::String::replace(romPath, "\\", "")))); @@ -1625,8 +1701,19 @@ void FileData::launchGame() LOG(LogDebug) << "Raw emulator launch command:"; LOG(LogDebug) << commandRaw; +#if defined(__ANDROID__) + LOG(LogInfo) << "Expanded emulator launch parameters:"; + LOG(LogInfo) << "Package: " << androidPackage; + LOG(LogInfo) << "Component: " + << (androidComponent == "" ? "" : androidComponent); + for (auto& extra : androidExtras) { + LOG(LogInfo) << "Extra name: " << extra.first; + LOG(LogInfo) << "Extra value: " << extra.second; + } +#else LOG(LogInfo) << "Expanded emulator launch command:"; LOG(LogInfo) << command; +#endif #if defined(FLATPAK_BUILD) // Break out of the sandbox. @@ -1645,8 +1732,11 @@ void FileData::launchGame() returnValue = Utils::Platform::launchGameWindows( Utils::String::stringToWideString(command), Utils::String::stringToWideString(startDirectory), runInBackground, hideWindow); +#elif defined(__ANDROID__) + returnValue = + Utils::Platform::Android::launchGame(androidPackage, androidComponent, androidExtras); #else - returnValue = Utils::Platform::launchGameUnix(command, startDirectory, runInBackground); +returnValue = Utils::Platform::launchGameUnix(command, startDirectory, runInBackground); #endif // Notify the user in case of a failed game launch using a popup window. if (returnValue != 0) { @@ -1737,23 +1827,27 @@ void FileData::launchGame() gameToUpdate->mSystem->onMetaDataSavePoint(); } -const std::string FileData::findEmulatorPath(std::string& command, const bool preCommand) +const std::pair FileData::findEmulator( + std::string& command, const bool preCommand) { // Extract the emulator executable from the launch command string. There are two ways // that the emulator can be defined in es_systems.xml, either using the find rules in - // es_find_rules.xml or via the explicit emulator binary name. In the former case, we + // es_find_rules.xml or via the explicit emulator name. In the former case, we // need to process any configured systempath and staticpath rules (and for Windows also // winregistrypath and winregistryvalue rules), and in the latter case we simply search - // for the emulator binary in the system path. + // for the emulator in the system path. std::string emuExecutable; std::string exePath; - // Method 1, emulator binary is defined using find rules: + // Method 1, emulator is defined using find rules: #if defined(_WIN64) std::vector emulatorWinRegistryPaths; std::vector emulatorWinRegistryValues; +#endif +#if defined(__ANDROID__) + std::vector emulatorAndroidPackages; #endif std::vector emulatorSystemPaths; std::vector emulatorStaticPaths; @@ -1782,6 +1876,10 @@ const std::string FileData::findEmulatorPath(std::string& command, const bool pr SystemData::sFindRules.get()->mEmulators[emulatorEntry].winRegistryPaths; emulatorWinRegistryValues = SystemData::sFindRules.get()->mEmulators[emulatorEntry].winRegistryValues; +#endif +#if defined(__ANDROID__) + emulatorAndroidPackages = + SystemData::sFindRules.get()->mEmulators[emulatorEntry].androidPackages; #endif emulatorSystemPaths = SystemData::sFindRules.get()->mEmulators[emulatorEntry].systemPaths; @@ -1793,10 +1891,13 @@ const std::string FileData::findEmulatorPath(std::string& command, const bool pr if (emulatorEntry != "" && emulatorWinRegistryPaths.empty() && emulatorWinRegistryValues.empty() && emulatorSystemPaths.empty() && emulatorStaticPaths.empty()) +#elif defined(__ANDROID__) + if (emulatorEntry != "" && emulatorAndroidPackages.empty() && emulatorSystemPaths.empty() && + emulatorStaticPaths.empty()) #else if (emulatorEntry != "" && emulatorSystemPaths.empty() && emulatorStaticPaths.empty()) #endif - return "NO EMULATOR RULE: " + emulatorEntry; + return std::make_pair(emulatorEntry, FileData::findEmulatorResult::NO_RULES); #if defined(_WIN64) for (std::string& path : emulatorWinRegistryPaths) { @@ -1834,19 +1935,19 @@ const std::string FileData::findEmulatorPath(std::string& command, const bool pr continue; } - // That a value was found does not guarantee that the emulator binary actually exists, - // so check for that as well. + // That a value was found does not guarantee that the emulator actually exists, so + // check for that as well. if (pathStatus == ERROR_SUCCESS) { if (Utils::FileSystem::isRegularFile(Utils::String::wideStringToString(registryPath)) || Utils::FileSystem::isSymlink(Utils::String::wideStringToString(registryPath))) { - LOG(LogDebug) << "FileData::findEmulatorPath(): " - << (preCommand ? "Pre-command binary" : "Emulator binary") + LOG(LogDebug) << "FileData::findEmulator(): " + << (preCommand ? "Pre-command" : "Emulator") << " found via winregistrypath rule"; exePath = Utils::FileSystem::getEscapedPath( Utils::String::wideStringToString(registryPath)); command.replace(startPos, endPos - startPos + 1, exePath); RegCloseKey(registryKey); - return exePath; + return std::make_pair(exePath, FileData::findEmulatorResult::FOUND_FILE); } } RegCloseKey(registryKey); @@ -1906,25 +2007,45 @@ const std::string FileData::findEmulatorPath(std::string& command, const bool pr if (!appendString.empty()) path.append(Utils::String::stringToWideString(appendString)); - // That a value was found does not guarantee that the emulator binary actually exists, + // That a value was found does not guarantee that the emulator actually exists, // so check for that as well. if (pathStatus == ERROR_SUCCESS) { if (Utils::FileSystem::isRegularFile(Utils::String::wideStringToString(path)) || Utils::FileSystem::isSymlink(Utils::String::wideStringToString(path))) { - LOG(LogDebug) << "FileData::findEmulatorPath(): " - << (preCommand ? "Pre-command binary" : "Emulator binary") + LOG(LogDebug) << "FileData::findEmulator(): " + << (preCommand ? "Pre-command" : "Emulator") << " found via winregistryvalue rule"; exePath = Utils::FileSystem::getEscapedPath(Utils::String::wideStringToString(path)); command.replace(startPos, endPos - startPos + 1, exePath); RegCloseKey(registryKey); - return exePath; + return std::make_pair(exePath, FileData::findEmulatorResult::FOUND_FILE); } } RegCloseKey(registryKey); } #endif +#if defined(__ANDROID__) + for (std::string& androidpackage : emulatorAndroidPackages) { + // If a pipe character is present in the androidpackage entry it means an explicit Intent + // component should be used rather than the default one. The checkEmulatorInstalled() + // Java function will check for the component as well and if it's not found it flags + // the overall emulator entry as not found. + std::string packageName {androidpackage}; + std::string component; + const size_t pipePos {packageName.find('|')}; + if (pipePos != std::string::npos) { + component = packageName.substr(pipePos + 1); + packageName = packageName.substr(0, pipePos); + } + if (Utils::Platform::Android::checkEmulatorInstalled(packageName, component)) { + return std::make_pair(androidpackage, + FileData::findEmulatorResult::FOUND_ANDROID_PACKAGE); + } + } +#endif + for (std::string& path : emulatorSystemPaths) { #if defined(_WIN64) std::wstring pathWide {Utils::String::stringToWideString(path)}; @@ -1945,30 +2066,30 @@ const std::string FileData::findEmulatorPath(std::string& command, const bool pr } } if (exePath != "") { - LOG(LogDebug) << "FileData::findEmulatorPath(): " - << (preCommand ? "Pre-command binary" : "Emulator binary") + LOG(LogDebug) << "FileData::findEmulator(): " + << (preCommand ? "Pre-command" : "Emulator") << " found via systempath rule"; exePath += "\\" + path; exePath = Utils::FileSystem::getEscapedPath(exePath); command.replace(startPos, endPos - startPos + 1, exePath); - return exePath; + return std::make_pair(exePath, FileData::findEmulatorResult::FOUND_FILE); } #else exePath = Utils::FileSystem::getPathToBinary(path); if (exePath != "") { - LOG(LogDebug) << "FileData::findEmulatorPath(): " - << (preCommand ? "Pre-command binary" : "Emulator binary") + LOG(LogDebug) << "FileData::findEmulator(): " + << (preCommand ? "Pre-command" : "Emulator") << " found via systempath rule"; exePath += "/" + path; command.replace(startPos, endPos - startPos + 1, exePath); - return exePath; + return std::make_pair(exePath, FileData::findEmulatorResult::FOUND_FILE); } #endif } for (std::string& path : emulatorStaticPaths) { // If a pipe character is present in the staticpath entry it means we should substitute - // the emulator binary with whatever is defined after the pipe character. + // the emulator with whatever is defined after the pipe character. std::string replaceCommand; const size_t pipePos {path.find('|')}; @@ -1998,23 +2119,23 @@ const std::string FileData::findEmulatorPath(std::string& command, const bool pr } if (Utils::FileSystem::isRegularFile(path) || Utils::FileSystem::isSymlink(path)) { - LOG(LogDebug) << "FileData::findEmulatorPath(): " - << (preCommand ? "Pre-command binary" : "Emulator binary") + LOG(LogDebug) << "FileData::findEmulator(): " + << (preCommand ? "Pre-command" : "Emulator") << " found via staticpath rule"; if (replaceCommand == "") { exePath = Utils::FileSystem::getEscapedPath(path); } else { - LOG(LogDebug) << "FileData::findEmulatorPath(): Replacing emulator binary in " + LOG(LogDebug) << "FileData::findEmulator(): Replacing emulator in " "staticpath rule with explicitly defined command"; exePath = replaceCommand; } command.replace(startPos, endPos - startPos + 1, exePath); - return exePath; + return std::make_pair(exePath, FileData::findEmulatorResult::FOUND_FILE); } } - // Method 2, exact emulator binary name: + // Method 2, exact emulator name: // If %ESPATH% is used, then expand it to the binary directory of ES-DE. command = Utils::String::replace(command, "%ESPATH%", Utils::FileSystem::getExePath()); @@ -2052,7 +2173,7 @@ const std::string FileData::findEmulatorPath(std::string& command, const bool pr exePath = Utils::String::wideStringToString(pathBuffer.data()); } -#else +#elif !defined(__ANDROID__) if (Utils::FileSystem::isRegularFile(emuExecutable) || Utils::FileSystem::isSymlink(emuExecutable)) { exePath = Utils::FileSystem::getEscapedPath(emuExecutable); @@ -2065,7 +2186,7 @@ const std::string FileData::findEmulatorPath(std::string& command, const bool pr } #endif - return exePath; + return std::make_pair(exePath, FileData::findEmulatorResult::NOT_FOUND); } CollectionFileData::CollectionFileData(FileData* file, SystemData* system) diff --git a/es-app/src/FileData.h b/es-app/src/FileData.h index 46aed47e3..982d73b88 100644 --- a/es-app/src/FileData.h +++ b/es-app/src/FileData.h @@ -123,8 +123,16 @@ public: virtual FileData* getSourceFileData() { return this; } const std::string& getSystemName() const { return mSystemName; } + enum class findEmulatorResult { + FOUND_FILE, + FOUND_ANDROID_PACKAGE, + NOT_FOUND, + NO_RULES + }; + void launchGame(); - const std::string findEmulatorPath(std::string& command, const bool preCommand); + const std::pair findEmulator(std::string& command, + const bool preCommand); using ComparisonFunction = bool(const FileData* a, const FileData* b); struct SortType { diff --git a/es-app/src/SystemData.cpp b/es-app/src/SystemData.cpp index b54e0b487..12f1c390a 100644 --- a/es-app/src/SystemData.cpp +++ b/es-app/src/SystemData.cpp @@ -56,6 +56,9 @@ void FindRules::loadFindRules() #elif defined(__APPLE__) filePath = ResourceManager::getInstance().getResourcePath(":/systems/macos/es_find_rules.xml", false); +#elif defined(__ANDROID__) + filePath = ResourceManager::getInstance().getResourcePath(":/systems/android/es_find_rules.xml", + false); #else filePath = ResourceManager::getInstance().getResourcePath(":/systems/unix/es_find_rules.xml", false); @@ -84,7 +87,6 @@ void FindRules::loadFindRules() #else const pugi::xml_parse_result& res {doc.load_file(path.c_str())}; #endif - if (!res) { LOG(LogError) << "Couldn't parse es_find_rules.xml: " << res.description(); continue; @@ -126,6 +128,9 @@ void FindRules::loadFindRules() #if defined(_WIN64) if (ruleType != "winregistrypath" && ruleType != "winregistryvalue" && ruleType != "systempath" && ruleType != "staticpath") { +#elif defined(__ANDROID__) + if (ruleType != "androidpackage" && ruleType != "systempath" && + ruleType != "staticpath") { #else if (ruleType != "systempath" && ruleType != "staticpath") { #endif @@ -145,6 +150,9 @@ void FindRules::loadFindRules() emulatorRules.winRegistryPaths.emplace_back(entryValue); else if (ruleType == "winregistryvalue") emulatorRules.winRegistryValues.emplace_back(entryValue); +#elif defined(__ANDROID__) + else if (ruleType == "androidpackage") + emulatorRules.androidPackages.emplace_back(entryValue); #endif } } @@ -154,6 +162,8 @@ void FindRules::loadFindRules() #if defined(_WIN64) emulatorRules.winRegistryPaths.clear(); emulatorRules.winRegistryValues.clear(); +#elif defined(__ANDROID__) + emulatorRules.androidPackages.clear(); #endif } @@ -969,6 +979,8 @@ std::vector SystemData::getConfigPath() path = ResourceManager::getInstance().getResourcePath(":/systems/windows/es_systems.xml", true); #elif defined(__APPLE__) path = ResourceManager::getInstance().getResourcePath(":/systems/macos/es_systems.xml", true); +#elif defined(__ANDROID__) + path = ResourceManager::getInstance().getResourcePath(":/systems/android/es_systems.xml", true); #else path = ResourceManager::getInstance().getResourcePath(":/systems/unix/es_systems.xml", true); #endif diff --git a/es-app/src/SystemData.h b/es-app/src/SystemData.h index c72889b56..d352b27d8 100644 --- a/es-app/src/SystemData.h +++ b/es-app/src/SystemData.h @@ -44,6 +44,8 @@ private: #if defined(_WIN64) std::vector winRegistryPaths; std::vector winRegistryValues; +#elif defined(__ANDROID__) + std::vector androidPackages; #endif std::vector systemPaths; std::vector staticPaths; diff --git a/es-core/src/utils/PlatformUtil.cpp b/es-core/src/utils/PlatformUtil.cpp index 8b00443c4..f09336b62 100644 --- a/es-core/src/utils/PlatformUtil.cpp +++ b/es-core/src/utils/PlatformUtil.cpp @@ -379,13 +379,60 @@ namespace Utils // TODO: Wait for interface to close and check actual outcome. JNIEnv* jniEnv {reinterpret_cast(SDL_AndroidGetJNIEnv())}; jclass jniClass {jniEnv->FindClass("org/esde/esde/esde")}; - jmethodID funcID { + jmethodID methodID { jniEnv->GetStaticMethodID(jniClass, "requestStoragePermissions", "()Z")}; const bool result { - static_cast(jniEnv->CallStaticBooleanMethod(jniClass, funcID))}; + static_cast(jniEnv->CallStaticBooleanMethod(jniClass, methodID))}; + // jniEnv->DeleteLocalRef(jniClass); return result; } + bool checkEmulatorInstalled(const std::string& packageName, + const std::string& component) + { + JNIEnv* jniEnv {reinterpret_cast(SDL_AndroidGetJNIEnv())}; + jclass jniClass {jniEnv->FindClass("org/esde/esde/esde")}; + jmethodID methodID {jniEnv->GetStaticMethodID( + jniClass, "checkEmulatorInstalled", "(Ljava/lang/String;Ljava/lang/String;)Z")}; + bool returnValue {static_cast(jniEnv->CallStaticBooleanMethod( + jniClass, methodID, jniEnv->NewStringUTF(packageName.c_str()), + jniEnv->NewStringUTF(component.c_str())))}; + // jniEnv->DeleteLocalRef(jniClass); + return returnValue; + } + + int launchGame(const std::string& packageName, + const std::string& component, + std::vector>& extras) + { + JNIEnv* jniEnv {reinterpret_cast(SDL_AndroidGetJNIEnv())}; + jclass jniClass {jniEnv->FindClass("org/esde/esde/esde")}; + jmethodID methodID {jniEnv->GetStaticMethodID( + jniClass, "launchGame", + "(Ljava/lang/String;Ljava/lang/String;Ljava/util/Vector;Ljava/util/Vector;)Z")}; + jclass vectorClass {jniEnv->FindClass("java/util/Vector")}; + jmethodID vectorMID {jniEnv->GetMethodID(vectorClass, "", "()V")}; + jmethodID addMethodID { + jniEnv->GetMethodID(vectorClass, "add", "(Ljava/lang/Object;)Z")}; + jobject extrasNames {jniEnv->NewObject(vectorClass, vectorMID)}; + jobject extrasValues {jniEnv->NewObject(vectorClass, vectorMID)}; + for (auto& extra : extras) { + jniEnv->CallBooleanMethod(extrasNames, addMethodID, + jniEnv->NewStringUTF(extra.first.c_str())); + jniEnv->CallBooleanMethod(extrasValues, addMethodID, + jniEnv->NewStringUTF(extra.second.c_str())); + } + const bool returnValue {static_cast(jniEnv->CallStaticBooleanMethod( + jniClass, methodID, jniEnv->NewStringUTF(packageName.c_str()), + jniEnv->NewStringUTF(component.c_str()), extrasNames, extrasValues))}; + // jniEnv->DeleteLocalRef(vectorClass); + // jniEnv->DeleteLocalRef(jniClass); + if (returnValue) + return -1; + else + return 0; + } + } // namespace Android #endif } // namespace Platform diff --git a/es-core/src/utils/PlatformUtil.h b/es-core/src/utils/PlatformUtil.h index a0f9a3fe4..723d0db64 100644 --- a/es-core/src/utils/PlatformUtil.h +++ b/es-core/src/utils/PlatformUtil.h @@ -60,7 +60,12 @@ namespace Utils namespace Android { bool requestStoragePermission(); - }; // namespace Android + bool checkEmulatorInstalled(const std::string& packageName, + const std::string& component); + int launchGame(const std::string& packageName, + const std::string& component, + std::vector>& extras); + } // namespace Android #endif static QuitMode sQuitMode = QuitMode::QUIT;