[Base] Cvars from Android Bundle/Intent
This commit is contained in:
parent
415750252b
commit
373b143049
|
@ -14,6 +14,13 @@ import org.jetbrains.annotations.Nullable;
|
||||||
import jp.xenia.XeniaRuntimeException;
|
import jp.xenia.XeniaRuntimeException;
|
||||||
|
|
||||||
public abstract class WindowedAppActivity extends Activity {
|
public abstract class WindowedAppActivity extends Activity {
|
||||||
|
// The EXTRA_CVARS value literal is also used in the native code.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the Bundle intent extra containing Xenia config variable launch arguments.
|
||||||
|
*/
|
||||||
|
public static final String EXTRA_CVARS = "jp.xenia.emulator.WindowedAppActivity.EXTRA_CVARS";
|
||||||
|
|
||||||
static {
|
static {
|
||||||
System.loadLibrary("xenia-app");
|
System.loadLibrary("xenia-app");
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,8 @@ extern "C" int main(int argc, char** argv) {
|
||||||
|
|
||||||
// Initialize Android globals, including logging. Needs parsed cvars.
|
// Initialize Android globals, including logging. Needs parsed cvars.
|
||||||
// TODO(Triang3l): Obtain the actual API level.
|
// TODO(Triang3l): Obtain the actual API level.
|
||||||
xe::InitializeAndroidAppFromMainThread(__ANDROID_API__, nullptr, nullptr);
|
xe::InitializeAndroidAppFromMainThread(__ANDROID_API__, nullptr, nullptr,
|
||||||
|
nullptr);
|
||||||
|
|
||||||
std::vector<std::string> args;
|
std::vector<std::string> args;
|
||||||
for (int n = 0; n < argc; n++) {
|
for (int n = 0; n < argc; n++) {
|
||||||
|
|
|
@ -7,9 +7,7 @@
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "cvar.h"
|
#include "xenia/base/cvar.h"
|
||||||
|
|
||||||
#include "utf8.h"
|
|
||||||
|
|
||||||
#define UTF_CPP_CPLUSPLUS 201703L
|
#define UTF_CPP_CPLUSPLUS 201703L
|
||||||
#include "third_party/utfcpp/source/utf8.h"
|
#include "third_party/utfcpp/source/utf8.h"
|
||||||
|
@ -17,6 +15,7 @@
|
||||||
#include "xenia/base/console.h"
|
#include "xenia/base/console.h"
|
||||||
#include "xenia/base/logging.h"
|
#include "xenia/base/logging.h"
|
||||||
#include "xenia/base/system.h"
|
#include "xenia/base/system.h"
|
||||||
|
#include "xenia/base/utf8.h"
|
||||||
|
|
||||||
namespace utfcpp = utf8;
|
namespace utfcpp = utf8;
|
||||||
|
|
||||||
|
|
|
@ -20,8 +20,13 @@
|
||||||
#include "third_party/fmt/include/fmt/format.h"
|
#include "third_party/fmt/include/fmt/format.h"
|
||||||
#include "xenia/base/assert.h"
|
#include "xenia/base/assert.h"
|
||||||
#include "xenia/base/filesystem.h"
|
#include "xenia/base/filesystem.h"
|
||||||
|
#include "xenia/base/platform.h"
|
||||||
#include "xenia/base/string_util.h"
|
#include "xenia/base/string_util.h"
|
||||||
|
|
||||||
|
#if XE_PLATFORM_ANDROID
|
||||||
|
#include <jni.h>
|
||||||
|
#endif // XE_PLATFORM_ANDROID
|
||||||
|
|
||||||
namespace cvar {
|
namespace cvar {
|
||||||
|
|
||||||
namespace toml {
|
namespace toml {
|
||||||
|
@ -56,6 +61,7 @@ class CommandVar : virtual public ICommandVar {
|
||||||
const std::string& description() const override;
|
const std::string& description() const override;
|
||||||
void AddToLaunchOptions(cxxopts::Options* options) override;
|
void AddToLaunchOptions(cxxopts::Options* options) override;
|
||||||
void LoadFromLaunchOptions(cxxopts::ParseResult* result) override;
|
void LoadFromLaunchOptions(cxxopts::ParseResult* result) override;
|
||||||
|
void SetCommandLineValue(T val);
|
||||||
T* current_value() { return current_value_; }
|
T* current_value() { return current_value_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -67,7 +73,6 @@ class CommandVar : virtual public ICommandVar {
|
||||||
T Convert(std::string val);
|
T Convert(std::string val);
|
||||||
static std::string ToString(T val);
|
static std::string ToString(T val);
|
||||||
void SetValue(T val);
|
void SetValue(T val);
|
||||||
void SetCommandLineValue(T val);
|
|
||||||
void UpdateValue() override;
|
void UpdateValue() override;
|
||||||
};
|
};
|
||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
|
@ -297,6 +302,9 @@ inline void AddCommandVar(ICommandVar* cv) {
|
||||||
void ParseLaunchArguments(int& argc, char**& argv,
|
void ParseLaunchArguments(int& argc, char**& argv,
|
||||||
const std::string_view positional_help,
|
const std::string_view positional_help,
|
||||||
const std::vector<std::string>& positional_options);
|
const std::vector<std::string>& positional_options);
|
||||||
|
#if XE_PLATFORM_ANDROID
|
||||||
|
void ParseLaunchArgumentsFromAndroidBundle(jobject bundle);
|
||||||
|
#endif // XE_PLATFORM_ANDROID
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
IConfigVar* define_configvar(const char* name, T* default_value,
|
IConfigVar* define_configvar(const char* name, T* default_value,
|
||||||
|
|
|
@ -0,0 +1,211 @@
|
||||||
|
/**
|
||||||
|
******************************************************************************
|
||||||
|
* Xenia : Xbox 360 Emulator Research Project *
|
||||||
|
******************************************************************************
|
||||||
|
* Copyright 2022 Ben Vanik. All rights reserved. *
|
||||||
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
||||||
|
******************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
|
#include "xenia/base/assert.h"
|
||||||
|
#include "xenia/base/cvar.h"
|
||||||
|
#include "xenia/base/main_android.h"
|
||||||
|
|
||||||
|
namespace cvar {
|
||||||
|
|
||||||
|
void ParseLaunchArgumentsFromAndroidBundle(jobject bundle) {
|
||||||
|
if (!ConfigVars) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEnv* jni_env = xe::GetAndroidThreadJniEnv();
|
||||||
|
if (!jni_env) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
jclass bundle_class = jni_env->GetObjectClass(bundle);
|
||||||
|
if (!bundle_class) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bool bundle_methods_obtained = true;
|
||||||
|
jmethodID bundle_get_boolean =
|
||||||
|
jni_env->GetMethodID(bundle_class, "getBoolean", "(Ljava/lang/String;)Z");
|
||||||
|
bundle_methods_obtained &= (bundle_get_boolean != nullptr);
|
||||||
|
jmethodID bundle_get_double =
|
||||||
|
jni_env->GetMethodID(bundle_class, "getDouble", "(Ljava/lang/String;)D");
|
||||||
|
bundle_methods_obtained &= (bundle_get_double != nullptr);
|
||||||
|
jmethodID bundle_get_int =
|
||||||
|
jni_env->GetMethodID(bundle_class, "getInt", "(Ljava/lang/String;)I");
|
||||||
|
bundle_methods_obtained &= (bundle_get_int != nullptr);
|
||||||
|
jmethodID bundle_get_long =
|
||||||
|
jni_env->GetMethodID(bundle_class, "getLong", "(Ljava/lang/String;)J");
|
||||||
|
bundle_methods_obtained &= (bundle_get_long != nullptr);
|
||||||
|
jmethodID bundle_get_string = jni_env->GetMethodID(
|
||||||
|
bundle_class, "getString", "(Ljava/lang/String;)Ljava/lang/String;");
|
||||||
|
bundle_methods_obtained &= (bundle_get_string != nullptr);
|
||||||
|
jmethodID bundle_key_set_method_id =
|
||||||
|
jni_env->GetMethodID(bundle_class, "keySet", "()Ljava/util/Set;");
|
||||||
|
bundle_methods_obtained &= (bundle_key_set_method_id != nullptr);
|
||||||
|
if (!bundle_methods_obtained) {
|
||||||
|
jni_env->DeleteLocalRef(bundle_class);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
jobject key_set = jni_env->CallObjectMethod(bundle, bundle_key_set_method_id);
|
||||||
|
if (!key_set) {
|
||||||
|
jni_env->DeleteLocalRef(bundle_class);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
jclass set_class = jni_env->GetObjectClass(key_set);
|
||||||
|
if (!set_class) {
|
||||||
|
jni_env->DeleteLocalRef(key_set);
|
||||||
|
jni_env->DeleteLocalRef(bundle_class);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bool set_methods_obtained = true;
|
||||||
|
jmethodID set_iterator_method_id =
|
||||||
|
jni_env->GetMethodID(set_class, "iterator", "()Ljava/util/Iterator;");
|
||||||
|
set_methods_obtained &= (set_iterator_method_id != nullptr);
|
||||||
|
if (!set_methods_obtained) {
|
||||||
|
jni_env->DeleteLocalRef(set_class);
|
||||||
|
jni_env->DeleteLocalRef(key_set);
|
||||||
|
jni_env->DeleteLocalRef(bundle_class);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
jobject key_set_iterator =
|
||||||
|
jni_env->CallObjectMethod(key_set, set_iterator_method_id);
|
||||||
|
if (!key_set_iterator) {
|
||||||
|
jni_env->DeleteLocalRef(set_class);
|
||||||
|
jni_env->DeleteLocalRef(key_set);
|
||||||
|
jni_env->DeleteLocalRef(bundle_class);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
jclass iterator_class = jni_env->GetObjectClass(key_set_iterator);
|
||||||
|
if (!iterator_class) {
|
||||||
|
jni_env->DeleteLocalRef(key_set_iterator);
|
||||||
|
jni_env->DeleteLocalRef(set_class);
|
||||||
|
jni_env->DeleteLocalRef(key_set);
|
||||||
|
jni_env->DeleteLocalRef(bundle_class);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bool iterator_methods_obtained = true;
|
||||||
|
jmethodID iterator_has_next =
|
||||||
|
jni_env->GetMethodID(iterator_class, "hasNext", "()Z");
|
||||||
|
iterator_methods_obtained &= (iterator_has_next != nullptr);
|
||||||
|
jmethodID iterator_next =
|
||||||
|
jni_env->GetMethodID(iterator_class, "next", "()Ljava/lang/Object;");
|
||||||
|
iterator_methods_obtained &= (iterator_next != nullptr);
|
||||||
|
if (!iterator_methods_obtained) {
|
||||||
|
jni_env->DeleteLocalRef(iterator_class);
|
||||||
|
jni_env->DeleteLocalRef(key_set_iterator);
|
||||||
|
jni_env->DeleteLocalRef(set_class);
|
||||||
|
jni_env->DeleteLocalRef(key_set);
|
||||||
|
jni_env->DeleteLocalRef(bundle_class);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (jni_env->CallBooleanMethod(key_set_iterator, iterator_has_next)) {
|
||||||
|
jstring key = reinterpret_cast<jstring>(
|
||||||
|
jni_env->CallObjectMethod(key_set_iterator, iterator_next));
|
||||||
|
if (!key) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const char* key_utf = jni_env->GetStringUTFChars(key, nullptr);
|
||||||
|
if (!key_utf) {
|
||||||
|
jni_env->DeleteLocalRef(key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto cvar_it = ConfigVars->find(key_utf);
|
||||||
|
jni_env->ReleaseStringUTFChars(key, key_utf);
|
||||||
|
// key_utf can't be used from now on.
|
||||||
|
if (cvar_it == ConfigVars->end()) {
|
||||||
|
jni_env->DeleteLocalRef(key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
IConfigVar* cvar = cvar_it->second;
|
||||||
|
auto cvar_bool = dynamic_cast<CommandVar<bool>*>(cvar);
|
||||||
|
if (cvar_bool) {
|
||||||
|
cvar_bool->SetCommandLineValue(
|
||||||
|
bool(jni_env->CallBooleanMethod(bundle, bundle_get_boolean, key)));
|
||||||
|
jni_env->DeleteLocalRef(key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto cvar_int32 = dynamic_cast<CommandVar<int32_t>*>(cvar);
|
||||||
|
if (cvar_int32) {
|
||||||
|
cvar_int32->SetCommandLineValue(
|
||||||
|
jni_env->CallIntMethod(bundle, bundle_get_int, key));
|
||||||
|
jni_env->DeleteLocalRef(key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto cvar_uint32 = dynamic_cast<CommandVar<uint32_t>*>(cvar);
|
||||||
|
if (cvar_uint32) {
|
||||||
|
cvar_uint32->SetCommandLineValue(
|
||||||
|
uint32_t(jni_env->CallIntMethod(bundle, bundle_get_int, key)));
|
||||||
|
jni_env->DeleteLocalRef(key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto cvar_uint64 = dynamic_cast<CommandVar<uint64_t>*>(cvar);
|
||||||
|
if (cvar_uint64) {
|
||||||
|
cvar_uint64->SetCommandLineValue(
|
||||||
|
uint64_t(jni_env->CallLongMethod(bundle, bundle_get_long, key)));
|
||||||
|
jni_env->DeleteLocalRef(key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto cvar_double = dynamic_cast<CommandVar<double>*>(cvar);
|
||||||
|
if (cvar_double) {
|
||||||
|
cvar_double->SetCommandLineValue(
|
||||||
|
jni_env->CallDoubleMethod(bundle, bundle_get_double, key));
|
||||||
|
jni_env->DeleteLocalRef(key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto cvar_string = dynamic_cast<CommandVar<std::string>*>(cvar);
|
||||||
|
if (cvar_string) {
|
||||||
|
jstring cvar_string_value = reinterpret_cast<jstring>(
|
||||||
|
jni_env->CallObjectMethod(bundle, bundle_get_string, key));
|
||||||
|
if (cvar_string_value) {
|
||||||
|
const char* cvar_string_value_utf =
|
||||||
|
jni_env->GetStringUTFChars(cvar_string_value, nullptr);
|
||||||
|
if (cvar_string_value_utf) {
|
||||||
|
cvar_string->SetCommandLineValue(cvar_string_value_utf);
|
||||||
|
jni_env->ReleaseStringUTFChars(cvar_string_value,
|
||||||
|
cvar_string_value_utf);
|
||||||
|
}
|
||||||
|
jni_env->DeleteLocalRef(cvar_string_value);
|
||||||
|
}
|
||||||
|
jni_env->DeleteLocalRef(key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto cvar_path = dynamic_cast<CommandVar<std::filesystem::path>*>(cvar);
|
||||||
|
if (cvar_path) {
|
||||||
|
jstring cvar_string_value = reinterpret_cast<jstring>(
|
||||||
|
jni_env->CallObjectMethod(bundle, bundle_get_string, key));
|
||||||
|
if (cvar_string_value) {
|
||||||
|
const char* cvar_string_value_utf =
|
||||||
|
jni_env->GetStringUTFChars(cvar_string_value, nullptr);
|
||||||
|
if (cvar_string_value_utf) {
|
||||||
|
cvar_path->SetCommandLineValue(cvar_string_value_utf);
|
||||||
|
jni_env->ReleaseStringUTFChars(cvar_string_value,
|
||||||
|
cvar_string_value_utf);
|
||||||
|
}
|
||||||
|
jni_env->DeleteLocalRef(cvar_string_value);
|
||||||
|
}
|
||||||
|
jni_env->DeleteLocalRef(key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
assert_always("Unsupported type of cvar {}", cvar->name().c_str());
|
||||||
|
jni_env->DeleteLocalRef(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
jni_env->DeleteLocalRef(iterator_class);
|
||||||
|
jni_env->DeleteLocalRef(key_set_iterator);
|
||||||
|
jni_env->DeleteLocalRef(set_class);
|
||||||
|
jni_env->DeleteLocalRef(key_set);
|
||||||
|
jni_env->DeleteLocalRef(bundle_class);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace cvar
|
|
@ -15,6 +15,7 @@
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
#include "xenia/base/assert.h"
|
#include "xenia/base/assert.h"
|
||||||
|
#include "xenia/base/cvar.h"
|
||||||
#include "xenia/base/logging.h"
|
#include "xenia/base/logging.h"
|
||||||
#include "xenia/base/memory.h"
|
#include "xenia/base/memory.h"
|
||||||
#include "xenia/base/system.h"
|
#include "xenia/base/system.h"
|
||||||
|
@ -44,7 +45,8 @@ static void AndroidThreadJNIEnvDestructor(void* jni_env_pointer) {
|
||||||
|
|
||||||
void InitializeAndroidAppFromMainThread(int32_t api_level,
|
void InitializeAndroidAppFromMainThread(int32_t api_level,
|
||||||
JNIEnv* main_thread_jni_env,
|
JNIEnv* main_thread_jni_env,
|
||||||
jobject application_context) {
|
jobject application_context,
|
||||||
|
jobject launch_arguments_bundle) {
|
||||||
if (android_initializations_++) {
|
if (android_initializations_++) {
|
||||||
// Already initialized for another component in the process.
|
// Already initialized for another component in the process.
|
||||||
return;
|
return;
|
||||||
|
@ -96,6 +98,11 @@ void InitializeAndroidAppFromMainThread(int32_t api_level,
|
||||||
// Logging uses threading.
|
// Logging uses threading.
|
||||||
xe::threading::AndroidInitialize();
|
xe::threading::AndroidInitialize();
|
||||||
|
|
||||||
|
// Initialize the cvars before logging.
|
||||||
|
if (launch_arguments_bundle) {
|
||||||
|
cvar::ParseLaunchArgumentsFromAndroidBundle(launch_arguments_bundle);
|
||||||
|
}
|
||||||
|
|
||||||
// Multiple apps can be launched within one process - don't pass the actual
|
// Multiple apps can be launched within one process - don't pass the actual
|
||||||
// app name.
|
// app name.
|
||||||
xe::InitializeLogging("xenia");
|
xe::InitializeLogging("xenia");
|
||||||
|
|
|
@ -31,7 +31,8 @@ namespace xe {
|
||||||
// must be called in `main`, with a null main thread JNI environment.
|
// must be called in `main`, with a null main thread JNI environment.
|
||||||
void InitializeAndroidAppFromMainThread(int32_t api_level,
|
void InitializeAndroidAppFromMainThread(int32_t api_level,
|
||||||
JNIEnv* main_thread_jni_env,
|
JNIEnv* main_thread_jni_env,
|
||||||
jobject application_context);
|
jobject application_context,
|
||||||
|
jobject launch_arguments_bundle);
|
||||||
void ShutdownAndroidAppFromMainThread();
|
void ShutdownAndroidAppFromMainThread();
|
||||||
|
|
||||||
// May be the minimum supported level if the initialization was done without a
|
// May be the minimum supported level if the initialization was done without a
|
||||||
|
|
|
@ -230,7 +230,7 @@ bool AndroidWindowedAppContext::Initialize(JNIEnv* ui_thread_jni_env,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the application context.
|
// Get activity methods needed for initialization.
|
||||||
jmethodID activity_get_application_context = ui_thread_jni_env_->GetMethodID(
|
jmethodID activity_get_application_context = ui_thread_jni_env_->GetMethodID(
|
||||||
activity_class_, "getApplicationContext", "()Landroid/content/Context;");
|
activity_class_, "getApplicationContext", "()Landroid/content/Context;");
|
||||||
if (!activity_get_application_context) {
|
if (!activity_get_application_context) {
|
||||||
|
@ -240,6 +240,16 @@ bool AndroidWindowedAppContext::Initialize(JNIEnv* ui_thread_jni_env,
|
||||||
Shutdown();
|
Shutdown();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
jmethodID activity_get_intent = ui_thread_jni_env_->GetMethodID(
|
||||||
|
activity_class_, "getIntent", "()Landroid/content/Intent;");
|
||||||
|
if (!activity_get_intent) {
|
||||||
|
__android_log_write(ANDROID_LOG_ERROR, "AndroidWindowedAppContext",
|
||||||
|
"Failed to get the getIntent method of the activity");
|
||||||
|
Shutdown();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the application context.
|
||||||
jobject application_context_init_ref = ui_thread_jni_env_->CallObjectMethod(
|
jobject application_context_init_ref = ui_thread_jni_env_->CallObjectMethod(
|
||||||
activity, activity_get_application_context);
|
activity, activity_get_application_context);
|
||||||
if (!application_context_init_ref) {
|
if (!application_context_init_ref) {
|
||||||
|
@ -250,11 +260,59 @@ bool AndroidWindowedAppContext::Initialize(JNIEnv* ui_thread_jni_env,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get the launch arguments.
|
||||||
|
jobject launch_arguments_bundle_init_ref = nullptr;
|
||||||
|
{
|
||||||
|
jobject intent_init_ref =
|
||||||
|
ui_thread_jni_env_->CallObjectMethod(activity, activity_get_intent);
|
||||||
|
if (!intent_init_ref) {
|
||||||
|
__android_log_write(
|
||||||
|
ANDROID_LOG_ERROR, "AndroidWindowedAppContext",
|
||||||
|
"Failed to get the intent that has started the activity");
|
||||||
|
} else {
|
||||||
|
jclass intent_class = ui_thread_jni_env_->GetObjectClass(intent_init_ref);
|
||||||
|
if (!intent_class) {
|
||||||
|
__android_log_write(ANDROID_LOG_ERROR, "AndroidWindowedAppContext",
|
||||||
|
"Failed to get the intent class");
|
||||||
|
} else {
|
||||||
|
jmethodID intent_get_bundle_extra = ui_thread_jni_env_->GetMethodID(
|
||||||
|
intent_class, "getBundleExtra",
|
||||||
|
"(Ljava/lang/String;)Landroid/os/Bundle;");
|
||||||
|
if (!intent_get_bundle_extra) {
|
||||||
|
__android_log_write(
|
||||||
|
ANDROID_LOG_ERROR, "AndroidWindowedAppContext",
|
||||||
|
"Failed to get the getBundleExtra method of the intent");
|
||||||
|
} else {
|
||||||
|
jstring launch_arguments_extra_name =
|
||||||
|
ui_thread_jni_env_->NewStringUTF(
|
||||||
|
"jp.xenia.emulator.WindowedAppActivity.EXTRA_CVARS");
|
||||||
|
if (!launch_arguments_extra_name) {
|
||||||
|
__android_log_write(
|
||||||
|
ANDROID_LOG_ERROR, "AndroidWindowedAppContext",
|
||||||
|
"Failed to create the launch arguments intent extra data name "
|
||||||
|
"string");
|
||||||
|
} else {
|
||||||
|
launch_arguments_bundle_init_ref =
|
||||||
|
ui_thread_jni_env_->CallObjectMethod(
|
||||||
|
intent_init_ref, intent_get_bundle_extra,
|
||||||
|
launch_arguments_extra_name);
|
||||||
|
ui_thread_jni_env_->DeleteLocalRef(launch_arguments_extra_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ui_thread_jni_env_->DeleteLocalRef(intent_class);
|
||||||
|
}
|
||||||
|
ui_thread_jni_env_->DeleteLocalRef(intent_init_ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Initialize Xenia globals that may depend on the base globals and logging.
|
// Initialize Xenia globals that may depend on the base globals and logging.
|
||||||
xe::InitializeAndroidAppFromMainThread(
|
xe::InitializeAndroidAppFromMainThread(
|
||||||
AConfiguration_getSdkVersion(configuration_), ui_thread_jni_env_,
|
AConfiguration_getSdkVersion(configuration_), ui_thread_jni_env_,
|
||||||
application_context_init_ref);
|
application_context_init_ref, launch_arguments_bundle_init_ref);
|
||||||
android_base_initialized_ = true;
|
android_base_initialized_ = true;
|
||||||
|
if (launch_arguments_bundle_init_ref) {
|
||||||
|
ui_thread_jni_env_->DeleteLocalRef(launch_arguments_bundle_init_ref);
|
||||||
|
}
|
||||||
ui_thread_jni_env_->DeleteLocalRef(application_context_init_ref);
|
ui_thread_jni_env_->DeleteLocalRef(application_context_init_ref);
|
||||||
|
|
||||||
// Initialize common windowed app JNI IDs.
|
// Initialize common windowed app JNI IDs.
|
||||||
|
|
Loading…
Reference in New Issue