diff --git a/distribution/changelog.txt b/distribution/changelog.txt index 15f587b757ef..a3ebe2a45cc1 100644 --- a/distribution/changelog.txt +++ b/distribution/changelog.txt @@ -1,6 +1,7 @@ 0.4.10 (in development) ------------------------------------------------------------------------ - Improved: [#21424] Extra viewports can now rotate independently from the main viewport. +- Improved: [#21561, #21631] Enable more features in Android build (plugins, networking, multiplayer, audio formats). - Improved: [#21599] Currency signs now use non-breaking spaces. - Change: [#21529] Classify “Southern Sands”, “Tiny Towers”, “Nevermore Park”, “Pacifica” as expert scenarios. - Fix: [#910] Extra viewport does not preserve the location when rotating. @@ -67,7 +68,7 @@ - Fix: [#21039] Text rendering bleeds pixels through windows. - Fix: [#21054] “No entrance” style is selected by default in the track designer. - Fix: [#21145] [Plugin] setInterval/setTimeout handle conflict. -- Fix: [#21157] [Plugin] Widgets do not redraw correctly when updating disabled or visibility state. +- Fix: [#21157] [Plugin] Widgets do not redraw correctly when updating disabled or visibility state. - Fix: [#21158] [Plugin] Potential crash using setInterval/setTimeout within the callback. - Fix: [#21171] [Plugin] Crash creating entities with no more entity slots available. - Fix: [#21178] Inca Lost City’s scenario description incorrectly states there are height restrictions. diff --git a/src/openrct2-android/app/build.gradle b/src/openrct2-android/app/build.gradle index fbd7d4b853da..5041a40b6bc4 100644 --- a/src/openrct2-android/app/build.gradle +++ b/src/openrct2-android/app/build.gradle @@ -17,7 +17,7 @@ android { arguments '-DANDROID_STL=c++_shared' targets 'openrct2', 'openrct2-ui', 'openrct2-cli' // abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' - abiFilters 'arm64-v8a' + abiFilters 'arm64-v8a', 'x86_64' } } } @@ -45,8 +45,8 @@ android { } dependencies { - implementation 'commons-io:commons-io:2.6' - implementation 'androidx.appcompat:appcompat:1.4.0' + implementation 'commons-io:commons-io:2.13.0' + implementation 'androidx.appcompat:appcompat:1.6.1' implementation fileTree(include: ['*.jar'], dir: 'libs') } diff --git a/src/openrct2-android/app/src/main/CMakeLists.txt b/src/openrct2-android/app/src/main/CMakeLists.txt index 54b77f329c01..bac4e3597062 100644 --- a/src/openrct2-android/app/src/main/CMakeLists.txt +++ b/src/openrct2-android/app/src/main/CMakeLists.txt @@ -20,7 +20,7 @@ endif() include(ExternalProject) ExternalProject_Add(libs - URL https://github.com/OpenRCT2/openrct2-dependencies-android/releases/download/v10/${ANDROID_ABI}-android-dynamic.tar.zst + URL https://github.com/OpenRCT2/openrct2-dependencies-android/releases/download/v11/${ANDROID_ABI}-android-dynamic.tar.zst SOURCE_DIR "${CMAKE_BINARY_DIR}/libs" @@ -29,6 +29,14 @@ ExternalProject_Add(libs INSTALL_COMMAND "" BUILD_BYPRODUCTS + ${CMAKE_BINARY_DIR}/libs/lib/${CMAKE_SHARED_LIBRARY_PREFIX}crypto${CMAKE_SHARED_LIBRARY_SUFFIX} + ${CMAKE_BINARY_DIR}/libs/lib/${CMAKE_SHARED_LIBRARY_PREFIX}vorbis${CMAKE_SHARED_LIBRARY_SUFFIX} + ${CMAKE_BINARY_DIR}/libs/lib/${CMAKE_SHARED_LIBRARY_PREFIX}vorbisfile${CMAKE_SHARED_LIBRARY_SUFFIX} + ${CMAKE_BINARY_DIR}/libs/lib/${CMAKE_SHARED_LIBRARY_PREFIX}FLAC${CMAKE_SHARED_LIBRARY_SUFFIX} + ${CMAKE_BINARY_DIR}/libs/lib/${CMAKE_SHARED_LIBRARY_PREFIX}brotlidec${CMAKE_SHARED_LIBRARY_SUFFIX} + ${CMAKE_BINARY_DIR}/libs/lib/${CMAKE_SHARED_LIBRARY_PREFIX}brotlicommon${CMAKE_SHARED_LIBRARY_SUFFIX} + ${CMAKE_BINARY_DIR}/libs/lib/${CMAKE_SHARED_LIBRARY_PREFIX}ogg${CMAKE_SHARED_LIBRARY_SUFFIX} + ${CMAKE_BINARY_DIR}/libs/lib/${CMAKE_SHARED_LIBRARY_PREFIX}bz2${CMAKE_SHARED_LIBRARY_SUFFIX} ${CMAKE_BINARY_DIR}/libs/lib/${CMAKE_SHARED_LIBRARY_PREFIX}freetype${CMAKE_SHARED_LIBRARY_SUFFIX} ${CMAKE_BINARY_DIR}/libs/lib/${CMAKE_SHARED_LIBRARY_PREFIX}png16${CMAKE_SHARED_LIBRARY_SUFFIX} ${CMAKE_BINARY_DIR}/libs/lib/${CMAKE_SHARED_LIBRARY_PREFIX}SDL2${CMAKE_SHARED_LIBRARY_SUFFIX} @@ -53,6 +61,14 @@ ExternalProject_Add(libs add_custom_command(TARGET libs POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} # COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_BINARY_DIR}/libs/lib/*.so" ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} + COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_BINARY_DIR}/libs/lib/libcrypto.so" ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} + COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_BINARY_DIR}/libs/lib/libvorbis.so" ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} + COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_BINARY_DIR}/libs/lib/libvorbisfile.so" ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} + COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_BINARY_DIR}/libs/lib/libFLAC.so" ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} + COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_BINARY_DIR}/libs/lib/libbrotlidec.so" ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} + COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_BINARY_DIR}/libs/lib/libbrotlicommon.so" ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} + COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_BINARY_DIR}/libs/lib/libogg.so" ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} + COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_BINARY_DIR}/libs/lib/libbz2.so" ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_BINARY_DIR}/libs/lib/libicudata.so" ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_BINARY_DIR}/libs/lib/libicuuc.so" ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_BINARY_DIR}/libs/lib/libicui18n.so" ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} @@ -124,13 +140,61 @@ set_target_properties(ssl PROPERTIES IMPORTED_LOCATION ) add_dependencies(ssl libs) +add_library(crypto SHARED IMPORTED) +set_target_properties(crypto PROPERTIES IMPORTED_LOCATION + ${CMAKE_BINARY_DIR}/libs/lib/${CMAKE_SHARED_LIBRARY_PREFIX}crypto${CMAKE_SHARED_LIBRARY_SUFFIX} +) +add_dependencies(crypto libs) + +add_library(vorbis SHARED IMPORTED) +set_target_properties(vorbis PROPERTIES IMPORTED_LOCATION + ${CMAKE_BINARY_DIR}/libs/lib/${CMAKE_SHARED_LIBRARY_PREFIX}vorbis${CMAKE_SHARED_LIBRARY_SUFFIX} +) +add_dependencies(vorbis libs) + +add_library(vorbisfile SHARED IMPORTED) +set_target_properties(vorbisfile PROPERTIES IMPORTED_LOCATION + ${CMAKE_BINARY_DIR}/libs/lib/${CMAKE_SHARED_LIBRARY_PREFIX}vorbisfile${CMAKE_SHARED_LIBRARY_SUFFIX} +) +add_dependencies(vorbisfile libs) + +add_library(FLAC SHARED IMPORTED) +set_target_properties(FLAC PROPERTIES IMPORTED_LOCATION + ${CMAKE_BINARY_DIR}/libs/lib/${CMAKE_SHARED_LIBRARY_PREFIX}FLAC${CMAKE_SHARED_LIBRARY_SUFFIX} +) +add_dependencies(FLAC libs) + +add_library(brotlidec SHARED IMPORTED) +set_target_properties(brotlidec PROPERTIES IMPORTED_LOCATION + ${CMAKE_BINARY_DIR}/libs/lib/${CMAKE_SHARED_LIBRARY_PREFIX}brotlidec${CMAKE_SHARED_LIBRARY_SUFFIX} +) +add_dependencies(brotlidec libs) + +add_library(brotlicommon SHARED IMPORTED) +set_target_properties(brotlicommon PROPERTIES IMPORTED_LOCATION + ${CMAKE_BINARY_DIR}/libs/lib/${CMAKE_SHARED_LIBRARY_PREFIX}brotlicommon${CMAKE_SHARED_LIBRARY_SUFFIX} +) +add_dependencies(brotlicommon libs) + +add_library(ogg SHARED IMPORTED) +set_target_properties(ogg PROPERTIES IMPORTED_LOCATION + ${CMAKE_BINARY_DIR}/libs/lib/${CMAKE_SHARED_LIBRARY_PREFIX}ogg${CMAKE_SHARED_LIBRARY_SUFFIX} +) +add_dependencies(ogg libs) + +add_library(bz2 SHARED IMPORTED) +set_target_properties(bz2 PROPERTIES IMPORTED_LOCATION + ${CMAKE_BINARY_DIR}/libs/lib/${CMAKE_SHARED_LIBRARY_PREFIX}bz2${CMAKE_SHARED_LIBRARY_SUFFIX} +) +add_dependencies(bz2 libs) + include_directories(SYSTEM "${CMAKE_BINARY_DIR}/libs/include") include_directories(SYSTEM "${CMAKE_BINARY_DIR}/libs/include/freetype2") include_directories(SYSTEM "${CMAKE_BINARY_DIR}/libs/include/SDL2") # now build app's shared lib -add_definitions(-DDISABLE_DISCORD_RPC -DDISABLE_HTTP -DDISABLE_NETWORK -DDISABLE_FLAC -DDISABLE_VORBIS -DDISABLE_OPENGL -DGL_GLEXT_PROTOTYPES -D__STDC_LIMIT_MACROS -DNO_TTF -DSDL_MAIN_HANDLED) +add_definitions(-DDISABLE_DISCORD_RPC -DDISABLE_OPENGL -DGL_GLEXT_PROTOTYPES -D__STDC_LIMIT_MACROS -DNO_TTF -DSDL_MAIN_HANDLED) # Enable scripting add_definitions(-DENABLE_SCRIPTING) @@ -183,10 +247,10 @@ file(GLOB_RECURSE OPENRCT2_CLI_SOURCES "${ORCT2_ROOT}/src/openrct2-cli/*.hpp") add_library(openrct2 SHARED ${LIBOPENRCT2_SOURCES}) -target_link_libraries(openrct2 android stdc++ log dl SDL2 png z icu icuuc icudata) +target_link_libraries(openrct2 android stdc++ log dl SDL2 png z icu icuuc icudata crypto ssl) add_library(openrct2-ui SHARED ${OPENRCT2_GUI_SOURCES}) -target_link_libraries(openrct2-ui openrct2 android stdc++ GLESv1_CM GLESv2 SDL2main speexdsp) +target_link_libraries(openrct2-ui openrct2 android stdc++ GLESv1_CM GLESv2 SDL2main speexdsp brotlicommon brotlidec bz2 freetype ogg vorbis vorbisfile FLAC) add_executable(openrct2-cli ${OPENRCT2_CLI_SOURCES}) target_link_libraries(openrct2-cli openrct2 android stdc++ GLESv1_CM GLESv2) diff --git a/src/openrct2-android/app/src/main/java/io/openrct2/GameActivity.java b/src/openrct2-android/app/src/main/java/io/openrct2/GameActivity.java index 56e51c4595e9..8ddfeaea6fc6 100644 --- a/src/openrct2-android/app/src/main/java/io/openrct2/GameActivity.java +++ b/src/openrct2-android/app/src/main/java/io/openrct2/GameActivity.java @@ -80,6 +80,8 @@ protected String[] getLibraries() { return new String[]{ "c++_shared", "speexdsp", + "bz2", + "freetype", "z", "png16", "SDL2", diff --git a/src/openrct2-android/app/src/main/java/io/openrct2/HttpAndroid.java b/src/openrct2-android/app/src/main/java/io/openrct2/HttpAndroid.java new file mode 100644 index 000000000000..ffb58a10623c --- /dev/null +++ b/src/openrct2-android/app/src/main/java/io/openrct2/HttpAndroid.java @@ -0,0 +1,122 @@ +package io.openrct2; + +import android.util.Log; + +import org.apache.commons.io.IOUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URL; +import java.net.HttpURLConnection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + + +public class HttpAndroid { + private static final String TAG = "HttpAndroid"; + + // Corresponding Java enum for the C++ 'Status' enum + public enum Status { + Invalid(0), + Ok(200), + NotFound(404); + + private final int code; + Status(int code) { + this.code = code; + } + + public int getCode() { + return code; + } + } + + // Corresponding Java enum for the C++ 'Method' enum + public enum Method { + GET, + POST, + PUT + } + + // Java class equivalent to the C++ 'Response' struct + public static class Response { + Status status; + String contentType; + String body; + Map> headers; + String error; + + } + + // Java class equivalent to the C++ 'Request' struct + public static class Request { + String url; + Map headers; + Method method; + String body; + boolean forceIPv4; + + public Request() { + this.method = Method.GET; // Default method + } + } + + public static Response request(Request request) { + Response response = new Response(); + response.status = Status.Invalid; + response.error = "Request failed"; + try { + InputStream inputStream = null; + try { + URL url = new URL(request.url); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod(request.method.toString()); + connection.setConnectTimeout(10000); + connection.setReadTimeout(10000); + connection.setUseCaches(false); + connection.setDoInput(true); + connection.setInstanceFollowRedirects(true); + if (request.headers != null) { + for (Map.Entry entry : request.headers.entrySet()) { + connection.setRequestProperty(entry.getKey(), entry.getValue()); + } + } + connection.connect(); + if (request.body!= null) { + OutputStream os = connection.getOutputStream(); + os.write(request.body.getBytes()); + os.flush(); + os.close(); + } + int responseCode = connection.getResponseCode(); + if (responseCode == 200) { + inputStream = connection.getInputStream(); + } else { + inputStream = connection.getErrorStream(); + } + // Log + Log.d(TAG, "Request: " + request.url + ", response code: " + responseCode); + response.status = Status.Ok; + response.contentType = connection.getContentType(); + response.headers = connection.getHeaderFields(); + response.body = IOUtils.toString(inputStream, "UTF-8"); + response.error = null; + return response; + } catch (IOException e) { + Log.e(TAG, "Error while requesting " + request.url + ", error: " + e.getMessage(), e); + response.error = e.getMessage(); + return response; + } finally { + if (inputStream != null) { + inputStream.close(); + } + } + } catch (IOException e) { + Log.e(TAG, "Error while requesting " + request.url, e); + response.error = e.getMessage(); + return response; + } + } +} diff --git a/src/openrct2/core/Http.Android.cpp b/src/openrct2/core/Http.Android.cpp new file mode 100644 index 000000000000..67cb15eafc70 --- /dev/null +++ b/src/openrct2/core/Http.Android.cpp @@ -0,0 +1,179 @@ +/***************************************************************************** + * Copyright (c) 2014-2024 OpenRCT2 developers + * + * For a complete list of all authors, please refer to contributors.md + * Interested in contributing? Visit https://github.com/OpenRCT2/OpenRCT2 + * + * OpenRCT2 is licensed under the GNU General Public License version 3. + *****************************************************************************/ + +#if !defined(DISABLE_HTTP) && defined(__ANDROID__) + +# include "Http.h" + +# include "../Version.h" +# include "../platform/Platform.h" + +# include +# include +# include + +# define OPENRCT2_USER_AGENT "OpenRCT2/" OPENRCT2_VERSION + +namespace Http +{ + Response Do(const Request& req) + { + std::map headers = req.header; + headers["User-Agent"] = OPENRCT2_USER_AGENT; + // Lambda to convert jstring to string + auto jstringToString = [](JNIEnv* env, jstring jstr) -> std::string { + if (jstr == nullptr) + { + return ""; + } + const char* cstr = env->GetStringUTFChars(jstr, nullptr); + std::string str = cstr; + env->ReleaseStringUTFChars(jstr, cstr); + return str; + }; + + JNIEnv* env = (JNIEnv*)SDL_AndroidGetJNIEnv(); + + // Create request object + + jclass HttpAndroidClass = Platform::AndroidFindClass(env, "io/openrct2/HttpAndroid"); + jclass req_class = Platform::AndroidFindClass(env, "io/openrct2/HttpAndroid$Request"); + // New request object + jobject jniRequest = env->NewObject(req_class, env->GetMethodID(req_class, "", "()V")); + // Create request's headers map + jobject jniHeaders = env->NewObject( + env->FindClass("java/util/HashMap"), + env->GetMethodID(env->GetObjectClass(env->FindClass("java/util/HashMap")), "", "()V")); + // HashMap's put method + jmethodID putMethod = env->GetMethodID( + env->FindClass("java/util/HashMap"), "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); + for (const auto& header : headers) + { + jstring jniKey = env->NewStringUTF(header.first.c_str()); + jstring jniValue = env->NewStringUTF(header.second.c_str()); + env->CallObjectMethod(jniHeaders, putMethod, jniKey, jniValue); + } + env->SetObjectField(jniRequest, env->GetFieldID(req_class, "headers", "Ljava/util/Map;"), jniHeaders); + + jstring req_body = req.body.empty() ? nullptr : env->NewStringUTF(req.body.c_str()); + jstring url = req.url.empty() ? nullptr : env->NewStringUTF(req.url.c_str()); + env->SetObjectField(jniRequest, env->GetFieldID(req_class, "body", "Ljava/lang/String;"), req_body); + env->SetObjectField(jniRequest, env->GetFieldID(req_class, "url", "Ljava/lang/String;"), url); + if (req_body != nullptr) + { + env->ReleaseStringUTFChars(req_body, env->GetStringUTFChars(req_body, nullptr)); + } + if (url != nullptr) + { + env->ReleaseStringUTFChars(url, env->GetStringUTFChars(url, nullptr)); + } + std::string method = "GET"; + switch (req.method) + { + case Method::GET: + method = "GET"; + break; + case Method::POST: + method = "POST"; + break; + case Method::PUT: + method = "PUT"; + break; + } + env->SetObjectField( + jniRequest, env->GetFieldID(req_class, "method", "Lio/openrct2/HttpAndroid$Method;"), + env->GetStaticObjectField( + Platform::AndroidFindClass(env, "io/openrct2/HttpAndroid$Method"), + env->GetStaticFieldID( + Platform::AndroidFindClass(env, "io/openrct2/HttpAndroid$Method"), method.c_str(), + "Lio/openrct2/HttpAndroid$Method;"))); + // Call request method + jmethodID requestMethod = env->GetStaticMethodID( + HttpAndroidClass, "request", "(Lio/openrct2/HttpAndroid$Request;)Lio/openrct2/HttpAndroid$Response;"); + jobject jniResponse = env->CallStaticObjectMethod(HttpAndroidClass, requestMethod, jniRequest); + jfieldID statusField = env->GetFieldID(env->GetObjectClass(jniResponse), "status", "Lio/openrct2/HttpAndroid$Status;"); + jobject jniStatus = env->GetObjectField(jniResponse, statusField); + jclass statusClass = Platform::AndroidFindClass(env, "io/openrct2/HttpAndroid$Status"); + jmethodID getCodeMethod = env->GetMethodID(statusClass, "getCode", "()I"); + int code = env->CallIntMethod(jniStatus, getCodeMethod); + + Response response; + + // Get response's headers field + jclass responseClass = env->GetObjectClass(jniResponse); + jfieldID headersField = env->GetFieldID(responseClass, "headers", "Ljava/util/Map;"); + jobject jniHeadersMap = env->GetObjectField(jniResponse, headersField); + + jmethodID entrySetMethod = env->GetMethodID(env->GetObjectClass(jniHeadersMap), "entrySet", "()Ljava/util/Set;"); + jobject jniEntrySet = env->CallObjectMethod(jniHeadersMap, entrySetMethod); + jmethodID iteratorMethod = env->GetMethodID(env->GetObjectClass(jniEntrySet), "iterator", "()Ljava/util/Iterator;"); + jobject jniIterator = env->CallObjectMethod(jniEntrySet, iteratorMethod); + jmethodID hasNextMethod = env->GetMethodID(env->GetObjectClass(jniIterator), "hasNext", "()Z"); + jmethodID nextMethod = env->GetMethodID(env->GetObjectClass(jniIterator), "next", "()Ljava/lang/Object;"); + while (env->CallBooleanMethod(jniIterator, hasNextMethod)) + { + jobject jniNext = env->CallObjectMethod(jniIterator, nextMethod); + jmethodID getKeyMethod = env->GetMethodID(env->GetObjectClass(jniNext), "getKey", "()Ljava/lang/Object;"); + jmethodID getValueMethod = env->GetMethodID(env->GetObjectClass(jniNext), "getValue", "()Ljava/lang/Object;"); + jobject jniKey = env->CallObjectMethod(jniNext, getKeyMethod); + // The first key is always null for some reason, its value contains the status code + if (jniKey == nullptr) + { + env->DeleteLocalRef(jniKey); + env->DeleteLocalRef(jniNext); + continue; + } + jobject jniValue = env->CallObjectMethod(jniNext, getValueMethod); + // convert jniValue to string + jmethodID valueToStringMethod = env->GetMethodID(env->GetObjectClass(jniValue), "toString", "()Ljava/lang/String;"); + jstring jniValueString = (jstring)env->CallObjectMethod(jniValue, valueToStringMethod); + jstring jniKeyString = (jstring)jniKey; + const char* jniKeyChars = env->GetStringUTFChars(jniKeyString, nullptr); + const char* jniValueChars = env->GetStringUTFChars(jniValueString, nullptr); + std::string value = jniValueChars; + std::string key = jniKeyChars; + env->ReleaseStringUTFChars(jniKeyString, jniKeyChars); + env->ReleaseStringUTFChars(jniValueString, jniValueChars); + response.header[key] = value; + + // Cleanup + env->DeleteLocalRef(jniValue); + env->DeleteLocalRef(jniKey); + env->DeleteLocalRef(jniNext); + } + // Get response's body field and convert it to string + jfieldID bodyField = env->GetFieldID(responseClass, "body", "Ljava/lang/String;"); + jstring jniBody = (jstring)env->GetObjectField(jniResponse, bodyField); + // Get response's error field and convert it to string + jfieldID errorField = env->GetFieldID(responseClass, "error", "Ljava/lang/String;"); + jstring jniError = (jstring)env->GetObjectField(jniResponse, errorField); + // Get response's content type field and convert it to string + jfieldID contentTypeField = env->GetFieldID(responseClass, "contentType", "Ljava/lang/String;"); + jstring jniContentType = (jstring)env->GetObjectField(jniResponse, contentTypeField); + // Prepare response + response.error = jstringToString(env, jniError); + response.content_type = jstringToString(env, jniContentType); + response.status = static_cast(code); + response.body = jstringToString(env, jniBody); + + env->DeleteLocalRef(jniResponse); + env->DeleteLocalRef(jniStatus); + env->DeleteLocalRef(jniHeadersMap); + env->DeleteLocalRef(jniBody); + env->DeleteLocalRef(jniContentType); + env->DeleteLocalRef(jniError); + env->DeleteLocalRef(jniHeaders); + env->DeleteLocalRef(jniRequest); + + return response; + } + +} // namespace Http + +#endif diff --git a/src/openrct2/core/Http.cURL.cpp b/src/openrct2/core/Http.cURL.cpp index aef20b41279f..67603998f941 100644 --- a/src/openrct2/core/Http.cURL.cpp +++ b/src/openrct2/core/Http.cURL.cpp @@ -7,7 +7,7 @@ * OpenRCT2 is licensed under the GNU General Public License version 3. *****************************************************************************/ -#if !defined(DISABLE_HTTP) && !defined(_WIN32) +#if !defined(DISABLE_HTTP) && !defined(_WIN32) && !defined(__ANDROID__) # include "Http.h"