diff --git a/android/jni/com/mapswithme/core/jni_helper.cpp b/android/jni/com/mapswithme/core/jni_helper.cpp index 667143d119..953aac16de 100644 --- a/android/jni/com/mapswithme/core/jni_helper.cpp +++ b/android/jni/com/mapswithme/core/jni_helper.cpp @@ -20,13 +20,13 @@ jclass g_bookmarkClazz; jclass g_myTrackerClazz; jclass g_httpClientClazz; jclass g_httpParamsClazz; -jclass g_httpHeaderClazz; jclass g_platformSocketClazz; jclass g_utilsClazz; jclass g_bannerClazz; jclass g_ratingClazz; -jclass g_arrayListClazz; jclass g_loggerFactoryClazz; +jclass g_keyValueClazz; +jclass g_httpUploaderClazz; extern "C" { @@ -44,12 +44,13 @@ JNI_OnLoad(JavaVM * jvm, void *) g_myTrackerClazz = jni::GetGlobalClassRef(env, "com/my/tracker/MyTracker"); g_httpClientClazz = jni::GetGlobalClassRef(env, "com/mapswithme/util/HttpClient"); g_httpParamsClazz = jni::GetGlobalClassRef(env, "com/mapswithme/util/HttpClient$Params"); - g_httpHeaderClazz = jni::GetGlobalClassRef(env, "com/mapswithme/util/HttpClient$HttpHeader"); g_platformSocketClazz = jni::GetGlobalClassRef(env, "com/mapswithme/maps/location/PlatformSocket"); g_utilsClazz = jni::GetGlobalClassRef(env, "com/mapswithme/util/Utils"); g_bannerClazz = jni::GetGlobalClassRef(env, "com/mapswithme/maps/ads/Banner"); g_ratingClazz = jni::GetGlobalClassRef(env, "com/mapswithme/maps/ugc/UGC$Rating"); g_loggerFactoryClazz = jni::GetGlobalClassRef(env, "com/mapswithme/util/log/LoggerFactory"); + g_keyValueClazz = jni::GetGlobalClassRef(env, "com/mapswithme/util/KeyValue"); + g_httpUploaderClazz = jni::GetGlobalClassRef(env, "com/mapswithme/util/HttpUploader"); return JNI_VERSION_1_6; } @@ -65,12 +66,13 @@ JNI_OnUnload(JavaVM *, void *) env->DeleteGlobalRef(g_myTrackerClazz); env->DeleteGlobalRef(g_httpClientClazz); env->DeleteGlobalRef(g_httpParamsClazz); - env->DeleteGlobalRef(g_httpHeaderClazz); env->DeleteGlobalRef(g_platformSocketClazz); env->DeleteGlobalRef(g_utilsClazz); env->DeleteGlobalRef(g_bannerClazz); env->DeleteGlobalRef(g_ratingClazz); env->DeleteGlobalRef(g_loggerFactoryClazz); + env->DeleteGlobalRef(g_keyValueClazz); + env->DeleteGlobalRef(g_httpUploaderClazz); } } // extern "C" @@ -286,4 +288,30 @@ void DumpDalvikReferenceTables() env->CallStaticVoidMethod(vm_class, dump_mid); env->DeleteLocalRef(vm_class); } + +jobject ToKeyValue(JNIEnv * env, std::pair src) +{ + static jmethodID const PairInit = jni::GetConstructorID( + env, g_keyValueClazz, "(Ljava/lang/String;Ljava/lang/String;)V"); + + jni::TScopedLocalRef key(env, jni::ToJavaString(env, src.first)); + jni::TScopedLocalRef value(env, jni::ToJavaString(env, src.second)); + + return env->NewObject(g_keyValueClazz, PairInit, key.get(), value.get()); +} + +std::pair ToNativeKeyValue(JNIEnv * env, jobject pairOfStrings) +{ + static jfieldID const keyId = env->GetFieldID(g_keyValueClazz, "key", + "Ljava/lang/String;"); + static jfieldID const valueId = env->GetFieldID(g_keyValueClazz, "value", + "Ljava/lang/String;"); + + jni::ScopedLocalRef const key( + env, static_cast(env->GetObjectField(pairOfStrings, keyId))); + jni::ScopedLocalRef const value( + env, static_cast(env->GetObjectField(pairOfStrings, valueId))); + + return { jni::ToNativeString(env, key.get()), jni::ToNativeString(env, value.get()) }; +} } // namespace jni diff --git a/android/jni/com/mapswithme/core/jni_helper.hpp b/android/jni/com/mapswithme/core/jni_helper.hpp index caea48b443..7ae359b5d8 100644 --- a/android/jni/com/mapswithme/core/jni_helper.hpp +++ b/android/jni/com/mapswithme/core/jni_helper.hpp @@ -10,6 +10,7 @@ #include #include +#include extern jclass g_mapObjectClazz; extern jclass g_featureIdClazz; @@ -17,12 +18,13 @@ extern jclass g_bookmarkClazz; extern jclass g_myTrackerClazz; extern jclass g_httpClientClazz; extern jclass g_httpParamsClazz; -extern jclass g_httpHeaderClazz; extern jclass g_platformSocketClazz; extern jclass g_utilsClazz; extern jclass g_bannerClazz; extern jclass g_ratingClazz; extern jclass g_loggerFactoryClazz; +extern jclass g_keyValueClazz; +extern jclass g_httpUploaderClazz; namespace jni { @@ -90,4 +92,28 @@ jobjectArray ToJavaArray(JNIEnv * env, jclass clazz, TContainer const & src, TTo jobjectArray ToJavaStringArray(JNIEnv * env, std::vector const & src); void DumpDalvikReferenceTables(); + +jobject ToKeyValue(JNIEnv * env, std::pair src); + +template +jobjectArray ToKeyValueArray(JNIEnv * env, Container const & src) +{ + return jni::ToJavaArray(env, g_keyValueClazz, src, + std::bind(&ToKeyValue, std::placeholders::_1, std::placeholders::_2)); +} + +std::pair ToNativeKeyValue(JNIEnv * env, jobject pairOfStrings); + +template +void ToNativekeyValueContainer(JNIEnv * env, jobjectArray src, OutputIt it) +{ + int const length = env->GetArrayLength(src); + for (size_t i = 0; i < length; ++i) + { + jni::ScopedLocalRef const arrayItem(env, env->GetObjectArrayElement(src, i)); + + *it = ToNativeKeyValue(env, arrayItem.get()); + ++it; + } +} } // namespace jni diff --git a/android/jni/com/mapswithme/platform/HttpUploader.cpp b/android/jni/com/mapswithme/platform/HttpUploader.cpp index 12fce40b41..6c79ac1ff3 100644 --- a/android/jni/com/mapswithme/platform/HttpUploader.cpp +++ b/android/jni/com/mapswithme/platform/HttpUploader.cpp @@ -1,12 +1,44 @@ +#include + +#include "com/mapswithme/core/jni_helper.hpp" +#include "com/mapswithme/core/ScopedEnv.hpp" +#include "com/mapswithme/core/ScopedLocalRef.hpp" + #include "platform/http_uploader.hpp" #include "base/assert.hpp" +#include +#include + namespace platform { void HttpUploader::Upload() const { - // Dummy implementation. CHECK(m_callback, ()); + auto env = jni::GetEnv(); + + CHECK(env, ()); + + static jmethodID const httpUploaderConstructor = + jni::GetConstructorID(env, g_httpUploaderClazz, "(Ljava/lang/String;Ljava/lang/String;" + "[Lcom/mapswithme/util/KeyValue;" + "[Lcom/mapswithme/util/KeyValue;" + "Ljava/lang/String;Ljava/lang/String;)V"); + + jni::ScopedLocalRef const method(env, jni::ToJavaString(env, m_method)); + jni::ScopedLocalRef const url(env, jni::ToJavaString(env, m_url)); + jni::ScopedLocalRef const params(env, jni::ToKeyValueArray(env, m_params)); + jni::ScopedLocalRef const headers(env, jni::ToKeyValueArray(env, m_headers)); + jni::ScopedLocalRef const fileKey(env, jni::ToJavaString(env, m_fileKey)); + jni::ScopedLocalRef const filePath(env, jni::ToJavaString(env, m_filePath)); + + jni::ScopedLocalRef const httpUploaderObject( + env, env->NewObject(g_httpUploaderClazz, httpUploaderConstructor, method.get(), url.get(), + params.get(), headers.get(), fileKey.get(), filePath.get())); + + static jmethodID const uploadId = jni::GetMethodID(env, httpUploaderObject, "upload", "()I"); + + m_callback(env->CallIntMethod(httpUploaderObject, uploadId), "dummy"); } } // namespace platform diff --git a/android/jni/com/mapswithme/util/HttpClient.cpp b/android/jni/com/mapswithme/util/HttpClient.cpp index 9302a5c309..aa1f0514e0 100644 --- a/android/jni/com/mapswithme/util/HttpClient.cpp +++ b/android/jni/com/mapswithme/util/HttpClient.cpp @@ -34,6 +34,7 @@ SOFTWARE. #include "base/logging.hpp" #include +#include #include DECLARE_EXCEPTION(JniException, RootException); @@ -103,22 +104,12 @@ void SetHeaders(ScopedEnv & env, jobject const params, if (headers.empty()) return; - static jmethodID const headerInit = jni::GetConstructorID( - env.get(), g_httpHeaderClazz, "(Ljava/lang/String;Ljava/lang/String;)V"); static jmethodID const setHeaders = env->GetMethodID( - g_httpParamsClazz, "setHeaders", "([Lcom/mapswithme/util/HttpClient$HttpHeader;)V"); + g_httpParamsClazz, "setHeaders", "([Lcom/mapswithme/util/KeyValue;)V"); RethrowOnJniException(env); - using HeaderPair = std::unordered_map::value_type; - auto headerFunc = [](JNIEnv * env, HeaderPair const & item) - { - jni::TScopedLocalRef first(env, jni::ToJavaString(env, item.first)); - jni::TScopedLocalRef second(env, jni::ToJavaString(env, item.second)); - return env->NewObject(g_httpHeaderClazz, headerInit, first.get(), second.get()); - }; - jni::TScopedLocalObjectArrayRef jHeaders(env.get(), jni::ToJavaArray(env.get(), g_httpHeaderClazz, - headers, headerFunc)); + jni::TScopedLocalObjectArrayRef jHeaders(env.get(), jni::ToKeyValueArray(env.get(), headers)); env->CallVoidMethod(params, setHeaders, jHeaders.get()); RethrowOnJniException(env); } @@ -127,8 +118,6 @@ void LoadHeaders(ScopedEnv & env, jobject const params, std::unordered_mapGetMethodID(g_httpParamsClazz, "getHeaders", "()[Ljava/lang/Object;"); - static jfieldID const keyId = env->GetFieldID(g_httpHeaderClazz, "key", "Ljava/lang/String;"); - static jfieldID const valueId = env->GetFieldID(g_httpHeaderClazz, "value", "Ljava/lang/String;"); jni::ScopedLocalRef const headersArray( env.get(), static_cast(env->CallObjectMethod(params, getHeaders))); @@ -136,20 +125,8 @@ void LoadHeaders(ScopedEnv & env, jobject const params, std::unordered_mapGetArrayLength(headersArray.get()); - for (size_t i = 0; i < length; ++i) - { - jni::ScopedLocalRef const headerEntry( - env.get(), env->GetObjectArrayElement(headersArray.get(), i)); + jni::ToNativekeyValueContainer(env.get(), headersArray, std::inserter(headers, headers.end())); - jni::ScopedLocalRef const key( - env.get(), static_cast(env->GetObjectField(headerEntry.get(), keyId))); - jni::ScopedLocalRef const value( - env.get(), static_cast(env->GetObjectField(headerEntry.get(), valueId))); - - headers.emplace(jni::ToNativeString(env.get(), key.get()), - jni::ToNativeString(env.get(), value.get())); - } RethrowOnJniException(env); } diff --git a/android/src/com/mapswithme/util/HttpClient.java b/android/src/com/mapswithme/util/HttpClient.java index f4dd464eb0..596acb1ac9 100644 --- a/android/src/com/mapswithme/util/HttpClient.java +++ b/android/src/com/mapswithme/util/HttpClient.java @@ -97,7 +97,7 @@ public final class HttpClient if (!TextUtils.isEmpty(p.cookies)) connection.setRequestProperty("Cookie", p.cookies); - for (HttpHeader header : p.headers) + for (KeyValue header : p.headers) { connection.setRequestProperty(header.key, header.value); } @@ -163,14 +163,14 @@ public final class HttpClient if (header.getKey() == null || header.getValue() == null) continue; - p.headers.add(new HttpHeader(header.getKey().toLowerCase(), TextUtils.join(", ", header.getValue()))); + p.headers.add(new KeyValue(header.getKey().toLowerCase(), TextUtils.join(", ", header.getValue()))); } } else { List cookies = connection.getHeaderFields().get("Set-Cookie"); if (cookies != null) - p.headers.add(new HttpHeader("Set-Cookie", TextUtils.join(", ", cookies))); + p.headers.add(new KeyValue("Set-Cookie", TextUtils.join(", ", cookies))); } OutputStream ostream; @@ -244,21 +244,9 @@ public final class HttpClient return url.replaceAll("(token|password|key)=([^&]+)", "***"); } - private static class HttpHeader - { - HttpHeader(@NonNull String key, @NonNull String value) - { - this.key = key; - this.value = value; - } - - public String key; - public String value; - } - private static class Params { - public void setHeaders(@NonNull HttpHeader[] array) + public void setHeaders(@NonNull KeyValue[] array) { headers = new ArrayList<>(Arrays.asList(array)); } @@ -282,7 +270,7 @@ public final class HttpClient // Received data is stored here if not null or in data otherwise. String outputFilePath; String cookies; - ArrayList headers = new ArrayList<>(); + ArrayList headers = new ArrayList<>(); int httpResponseCode = -1; boolean followRedirects = true; boolean loadHeaders; diff --git a/android/src/com/mapswithme/util/HttpUploader.java b/android/src/com/mapswithme/util/HttpUploader.java new file mode 100644 index 0000000000..7f3dad2146 --- /dev/null +++ b/android/src/com/mapswithme/util/HttpUploader.java @@ -0,0 +1,41 @@ +package com.mapswithme.util; + +import android.support.annotation.NonNull; + +import java.util.ArrayList; +import java.util.Arrays; + +final class HttpUploader +{ + @NonNull + private final String mMethod; + @NonNull + private final String mUrl; + @NonNull + private final ArrayList mParams; + @NonNull + private final ArrayList mHeaders; + @NonNull + private final String mFileKey; + @NonNull + private final String mFilePath; + + @SuppressWarnings("unused") + private HttpUploader(@NonNull String method, @NonNull String url, @NonNull KeyValue[] params, + @NonNull KeyValue[] headers, @NonNull String fileKey, @NonNull String filePath) + { + mMethod = method; + mUrl = url; + mParams = new ArrayList<>(Arrays.asList(params)); + mHeaders = new ArrayList<>(Arrays.asList(headers)); + mFileKey = fileKey; + mFilePath = filePath; + } + + @SuppressWarnings("unused") + private int upload() + { + // Dummy. Error code 200 - Http OK. + return 200; + } +} diff --git a/android/src/com/mapswithme/util/KeyValue.java b/android/src/com/mapswithme/util/KeyValue.java new file mode 100644 index 0000000000..ce052e5e81 --- /dev/null +++ b/android/src/com/mapswithme/util/KeyValue.java @@ -0,0 +1,17 @@ +package com.mapswithme.util; + +import android.support.annotation.NonNull; + +final class KeyValue +{ + KeyValue(@NonNull String key, @NonNull String value) + { + this.key = key; + this.value = value; + } + + @NonNull + public final String key; + @NonNull + public final String value; +} diff --git a/platform/http_uploader.hpp b/platform/http_uploader.hpp index 50ab5c0669..96d74be2e1 100644 --- a/platform/http_uploader.hpp +++ b/platform/http_uploader.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include