// SPDX-License-Identifier: MPL-2.0 // Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/) #pragma once #include "common.h" #include namespace skyline { struct DhcpInfo { i32 ipAddress; i32 subnet; i32 gateway; i32 dns1; i32 dns2; }; /** * @brief A wrapper over std::string that supports construction using a JNI jstring */ class JniString : public std::string { private: static std::string GetJString(JNIEnv *env, jstring jString); public: JniString(JNIEnv *env, jstring jString) : std::string(GetJString(env, jString)) {} }; /** * @brief A wrapper over the `Settings` Kotlin class * @note The lifetime of this class must not exceed that of the JNI environment * @note Copy construction of this class is disallowed to avoid issues with the JNI environment lifetime */ class KtSettings { private: JNIEnv *env; //!< A pointer to the current jni environment jclass settingsClass; //!< The settings class jobject settingsInstance; //!< The settings instance public: KtSettings(JNIEnv *env, jobject settingsInstance) : env(env), settingsInstance(settingsInstance), settingsClass(env->GetObjectClass(settingsInstance)) {} KtSettings(const KtSettings &) = delete; void operator=(const KtSettings &) = delete; KtSettings(KtSettings &&) = default; /** * @param key A null terminated string containing the key of the setting to get */ template requires std::is_integral_v || std::is_enum_v T GetInt(const std::string_view &key) { return static_cast(env->GetIntField(settingsInstance, env->GetFieldID(settingsClass, key.data(), "I"))); } /** * @param key A null terminated string containing the key of the setting to get */ bool GetBool(const std::string_view &key) { return env->GetBooleanField(settingsInstance, env->GetFieldID(settingsClass, key.data(), "Z")) == JNI_TRUE; } /** * @param key A null terminated string containing the key of the setting to get */ JniString GetString(const std::string_view &key) { return {env, static_cast(env->GetObjectField(settingsInstance, env->GetFieldID(settingsClass, key.data(), "Ljava/lang/String;")))}; } }; /** * @brief The JvmManager class is used to simplify transactions with the Java component */ class JvmManager { public: using KeyboardHandle = jobject; using KeyboardConfig = std::array; using KeyboardCloseResult = u32; using KeyboardTextCheckResult = u32; jobject instance; //!< A reference to the activity jclass instanceClass; //!< The class of the activity /** * @param env A pointer to the JNI environment * @param instance A reference to the activity */ JvmManager(JNIEnv *env, jobject instance); ~JvmManager(); /** * @brief Returns a pointer to the JNI environment for the current thread */ static JNIEnv *GetEnv(); /** * @brief Retrieves a specific field of the given type from the activity * @tparam objectType The type of the object in the field * @param key The name of the field in the activity class * @return The contents of the field as objectType */ template objectType GetField(const char *key) { JNIEnv *env{GetEnv()}; if constexpr(std::is_same()) return env->GetBooleanField(instance, env->GetFieldID(instanceClass, key, "Z")); else if constexpr(std::is_same()) return env->GetByteField(instance, env->GetFieldID(instanceClass, key, "B")); else if constexpr(std::is_same()) return env->GetCharField(instance, env->GetFieldID(instanceClass, key, "C")); else if constexpr(std::is_same()) return env->GetShortField(instance, env->GetFieldID(instanceClass, key, "S")); else if constexpr(std::is_same()) return env->GetIntField(instance, env->GetFieldID(instanceClass, key, "I")); else if constexpr(std::is_same()) return env->GetLongField(instance, env->GetFieldID(instanceClass, key, "J")); else if constexpr(std::is_same()) return env->GetFloatField(instance, env->GetFieldID(instanceClass, key, "F")); else if constexpr(std::is_same()) return env->GetDoubleField(instance, env->GetFieldID(instanceClass, key, "D")); else throw exception("GetField: Unhandled object type"); } /** * @brief Retrieves a specific field from the activity as a jobject * @param key The name of the field in the activity class * @param signature The signature of the field * @return A jobject of the contents of the field */ jobject GetField(const char *key, const char *signature); /** * @brief Checks if a specific field from the activity is null or not * @param key The name of the field in the activity class * @param signature The signature of the field * @return If the field is null or not */ bool CheckNull(const char *key, const char *signature); /** * @brief Checks if a specific jobject is null or not * @param object The jobject to check * @return If the object is null or not */ static bool CheckNull(jobject &object); /** * @brief A call to EmulationActivity.initializeControllers in Kotlin */ void InitializeControllers(); /** * @brief A call to EmulationActivity.vibrateDevice in Kotlin */ void VibrateDevice(jint index, const span &timings, const span &litudes); /** * @brief A call to EmulationActivity.clearVibrationDevice in Kotlin */ void ClearVibrationDevice(jint index); /** * @brief A call to EmulationActivity.showKeyboard in Kotlin */ KeyboardHandle ShowKeyboard(KeyboardConfig &config, std::u16string initialText); /** * @brief A call to EmulationActivity.waitForSubmitOrCancel in Kotlin */ std::pair WaitForSubmitOrCancel(KeyboardHandle dialog); /** * @brief A call to EmulationActivity.closeKeyboard in Kotlin */ void CloseKeyboard(KeyboardHandle dialog); /** * @brief A call to EmulationActivity.showValidationResult in Kotlin */ KeyboardCloseResult ShowValidationResult(KeyboardHandle dialog, KeyboardTextCheckResult checkResult, std::u16string message); /** * @brief A call to EmulationActivity.reportCrash in Kotlin */ void reportCrash(); /** * @brief A call to EmulationActivity.showPipelineLoadingScreen in Kotlin */ void ShowPipelineLoadingScreen(u32 totalPipelineCount); /** * @brief A call to EmulationActivity.updatePipelineLoadingProgress in Kotlin */ void UpdatePipelineLoadingProgress(u32 progress); /** * @brief A call to EmulationActivity.hidePipelineLoadingScreen in Kotlin */ void HidePipelineLoadingScreen(); /** * @brief A call to EmulationActivity.getVersionCode in Kotlin * @return A version code in Vulkan's format with 14-bit patch + 10-bit major and minor components */ i32 GetVersionCode(); /** * @brief A call to EmulationActivity.getDhcpInfo in Kotlin */ DhcpInfo GetDhcpInfo(); private: jmethodID initializeControllersId; jmethodID vibrateDeviceId; jmethodID clearVibrationDeviceId; jmethodID showKeyboardId; jmethodID waitForSubmitOrCancelId; jmethodID closeKeyboardId; jmethodID showValidationResultId; jmethodID getIntegerValueId; jmethodID reportCrashId; jmethodID showPipelineLoadingScreenId; jmethodID updatePipelineLoadingProgressId; jmethodID hidePipelineLoadingScreenId; jmethodID getVersionCodeId; jmethodID getDhcpInfoId; }; }