diff --git a/android/jni/CMakeLists.txt b/android/jni/CMakeLists.txt index 985781e5b6..42824e5a39 100644 --- a/android/jni/CMakeLists.txt +++ b/android/jni/CMakeLists.txt @@ -90,6 +90,7 @@ set( com/mapswithme/util/GeoUtils.cpp com/mapswithme/util/HttpClient.cpp com/mapswithme/util/HttpUploader.cpp + com/mapswithme/util/HttpUploaderBackground.cpp com/mapswithme/util/Language.cpp com/mapswithme/util/LoggerFactory.cpp com/mapswithme/util/NetworkPolicy.cpp diff --git a/android/jni/com/mapswithme/core/jni_helper.cpp b/android/jni/com/mapswithme/core/jni_helper.cpp index bb831a1230..b2674a7a92 100644 --- a/android/jni/com/mapswithme/core/jni_helper.cpp +++ b/android/jni/com/mapswithme/core/jni_helper.cpp @@ -27,6 +27,7 @@ jclass g_ratingClazz; jclass g_loggerFactoryClazz; jclass g_keyValueClazz; jclass g_httpUploaderClazz; +jclass g_httpUploaderBackgroundClazz; jclass g_httpUploaderResultClazz; jclass g_networkPolicyClazz; jclass g_storageUtilsClazz; @@ -54,6 +55,7 @@ JNI_OnLoad(JavaVM * jvm, void *) 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"); + g_httpUploaderBackgroundClazz = jni::GetGlobalClassRef(env, "com/mapswithme/util/HttpBackgroundUploader"); g_httpUploaderResultClazz = jni::GetGlobalClassRef(env, "com/mapswithme/util/HttpUploader$Result"); g_networkPolicyClazz = jni::GetGlobalClassRef(env, "com/mapswithme/util/NetworkPolicy"); g_storageUtilsClazz = jni::GetGlobalClassRef(env, "com/mapswithme/util/StorageUtils"); @@ -79,6 +81,7 @@ JNI_OnUnload(JavaVM *, void *) env->DeleteGlobalRef(g_loggerFactoryClazz); env->DeleteGlobalRef(g_keyValueClazz); env->DeleteGlobalRef(g_httpUploaderClazz); + env->DeleteGlobalRef(g_httpUploaderBackgroundClazz); env->DeleteGlobalRef(g_httpUploaderResultClazz); env->DeleteGlobalRef(g_networkPolicyClazz); env->DeleteGlobalRef(g_storageUtilsClazz); diff --git a/android/jni/com/mapswithme/core/jni_helper.hpp b/android/jni/com/mapswithme/core/jni_helper.hpp index 5fbac92a56..0eedd03d0a 100644 --- a/android/jni/com/mapswithme/core/jni_helper.hpp +++ b/android/jni/com/mapswithme/core/jni_helper.hpp @@ -28,6 +28,7 @@ extern jclass g_ratingClazz; extern jclass g_loggerFactoryClazz; extern jclass g_keyValueClazz; extern jclass g_httpUploaderClazz; +extern jclass g_httpUploaderBackgroundClazz; extern jclass g_httpUploaderResultClazz; extern jclass g_networkPolicyClazz; extern jclass g_storageUtilsClazz; diff --git a/android/jni/com/mapswithme/util/HttpUploaderBackground.cpp b/android/jni/com/mapswithme/util/HttpUploaderBackground.cpp new file mode 100644 index 0000000000..0271bb40f3 --- /dev/null +++ b/android/jni/com/mapswithme/util/HttpUploaderBackground.cpp @@ -0,0 +1,51 @@ +#include + +#include "com/mapswithme/core/ScopedEnv.hpp" +#include "com/mapswithme/core/ScopedLocalRef.hpp" +#include "com/mapswithme/core/jni_helper.hpp" + +#include "platform/http_uploader_background.hpp" + +#include "base/assert.hpp" + +#include +#include + +#include "private.h" + +namespace platform +{ +void HttpUploaderBackground::Upload() const +{ + JNIEnv* env = jni::GetEnv(); + + CHECK(env, ()); + + static jmethodID const httpUploaderConstructor = + jni::GetConstructorID(env, g_httpUploaderBackgroundClazz, + "(Ljava/lang/String;Ljava/lang/String;" + "[Lcom/mapswithme/util/KeyValue;" + "[Lcom/mapswithme/util/KeyValue;" + "Ljava/lang/String;Ljava/lang/String;Z)V"); + HttpPayload const payload = GetPayload(); + jni::ScopedLocalRef const method(env, jni::ToJavaString(env, payload.m_method)); + jni::ScopedLocalRef const url(env, jni::ToJavaString(env, payload.m_url)); + jni::ScopedLocalRef const params(env, jni::ToKeyValueArray(env, payload.m_params)); + jni::ScopedLocalRef const headers(env, + jni::ToKeyValueArray(env, payload.m_headers)); + jni::ScopedLocalRef const fileKey(env, jni::ToJavaString(env, payload.m_fileKey)); + jni::ScopedLocalRef const filePath(env, jni::ToJavaString(env, payload.m_filePath)); + + jni::ScopedLocalRef const httpUploaderObject( + env, env->NewObject(g_httpUploaderBackgroundClazz, httpUploaderConstructor, method.get(), url.get(), + params.get(), headers.get(), fileKey.get(), filePath.get(), + static_cast(payload.m_needClientAuth))); + + static jmethodID const uploadId = jni::GetMethodID(env, httpUploaderObject, "upload", "()V"); + env->CallVoidMethod(httpUploaderObject, uploadId); +} +} // namespace platform + +extern "C" +{ +} diff --git a/android/multidex-config.txt b/android/multidex-config.txt index f86f710c6e..a9f666364a 100644 --- a/android/multidex-config.txt +++ b/android/multidex-config.txt @@ -10,6 +10,7 @@ com/mapswithme/util/HttpClient$Params.class com/mapswithme/util/HttpClient.class com/mapswithme/util/HttpUploader$Result.class com/mapswithme/util/HttpUploader.class +com/mapswithme/util/HttpBackgroundUploader.class com/mapswithme/util/KeyValue.class com/mapswithme/util/log/LoggerFactory.class com/mapswithme/util/NetworkPolicy.class diff --git a/android/src/com/mapswithme/util/AbstractHttpUploader.java b/android/src/com/mapswithme/util/AbstractHttpUploader.java new file mode 100644 index 0000000000..3a6db6375f --- /dev/null +++ b/android/src/com/mapswithme/util/AbstractHttpUploader.java @@ -0,0 +1,75 @@ +package com.mapswithme.util; + +import androidx.annotation.NonNull; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public abstract class AbstractHttpUploader +{ + @NonNull + private final String mMethod; + @NonNull + private final String mUrl; + @NonNull + private final List mParams; + @NonNull + private final List mHeaders; + @NonNull + private final String mFileKey; + @NonNull + private final String mFilePath; + + private final boolean mNeedClientAuth; + + AbstractHttpUploader(@NonNull String method, @NonNull String url, + @NonNull KeyValue[] params, + @NonNull KeyValue[] headers, @NonNull String fileKey, + @NonNull String filePath, + boolean needClientAuth) + { + mMethod = method; + mUrl = url; + mFileKey = fileKey; + mFilePath = filePath; + mParams = new ArrayList<>(Arrays.asList(params)); + mHeaders = new ArrayList<>(Arrays.asList(headers)); + mNeedClientAuth = needClientAuth; + } + + @NonNull + protected String getMethod() { + return mMethod; + } + + @NonNull + protected String getUrl() { + return mUrl; + } + + @NonNull + protected List getParams() { + return mParams; + } + + @NonNull + protected List getHeaders() { + return mHeaders; + } + + @NonNull + protected String getFileKey() { + return mFileKey; + } + + @NonNull + protected String getFilePath() { + return mFilePath; + } + + protected boolean needClientAuth() { + return mNeedClientAuth; + } + +} diff --git a/android/src/com/mapswithme/util/HttpBackgroundUploader.java b/android/src/com/mapswithme/util/HttpBackgroundUploader.java new file mode 100644 index 0000000000..bef5ecc9d0 --- /dev/null +++ b/android/src/com/mapswithme/util/HttpBackgroundUploader.java @@ -0,0 +1,21 @@ +package com.mapswithme.util; + +import androidx.annotation.NonNull; + +public class HttpBackgroundUploader extends AbstractHttpUploader +{ + + public HttpBackgroundUploader(@NonNull String method, @NonNull String url, + @NonNull KeyValue[] params, + @NonNull KeyValue[] headers, @NonNull String fileKey, + @NonNull String filePath, + boolean needClientAuth) + { + super(method, url, params, headers, fileKey, filePath, needClientAuth); + } + + public void upload() + { + /* WorkManager */ + } +} diff --git a/android/src/com/mapswithme/util/HttpUploader.java b/android/src/com/mapswithme/util/HttpUploader.java index 910fd3b55a..cb11c446e5 100644 --- a/android/src/com/mapswithme/util/HttpUploader.java +++ b/android/src/com/mapswithme/util/HttpUploader.java @@ -1,18 +1,17 @@ package com.mapswithme.util; import android.os.Build; +import android.text.TextUtils; +import android.util.Base64; + import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import android.text.TextUtils; -import android.util.Base64; import com.mapswithme.maps.BuildConfig; import com.mapswithme.maps.Framework; import com.mapswithme.util.log.Logger; import com.mapswithme.util.log.LoggerFactory; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLSocketFactory; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; @@ -25,11 +24,11 @@ import java.io.PrintWriter; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -public final class HttpUploader +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSocketFactory; + +public final class HttpUploader extends AbstractHttpUploader { private static final Logger LOGGER = LoggerFactory.INSTANCE.getLogger(LoggerFactory.Type.NETWORK); private static final String TAG = HttpUploader.class.getSimpleName(); @@ -37,37 +36,19 @@ public final class HttpUploader private static final String CHARSET = "UTF-8"; private static final int BUFFER = 8192; private static final int STATUS_CODE_UNKNOWN = -1; - @NonNull - private final String mMethod; - @NonNull - private final String mUrl; - @NonNull - private final List mParams; - @NonNull - private final List mHeaders; - @NonNull - private final String mFileKey; - @NonNull - private final String mFilePath; + @NonNull private final String mBoundary; @NonNull private final String mEndPart; - private final boolean mNeedClientAuth; public HttpUploader(@NonNull String method, @NonNull String url, @NonNull KeyValue[] params, @NonNull KeyValue[] headers, @NonNull String fileKey, @NonNull String filePath, boolean needClientAuth) { - mMethod = method; - mUrl = url; - mFileKey = fileKey; - mFilePath = filePath; + super(method, url, params, headers, fileKey, filePath, needClientAuth); mBoundary = "----" + System.currentTimeMillis(); - mParams = new ArrayList<>(Arrays.asList(params)); - mHeaders = new ArrayList<>(Arrays.asList(headers)); mEndPart = LINE_FEED + "--" + mBoundary + "--" + LINE_FEED; - mNeedClientAuth = needClientAuth; } public Result upload() @@ -79,14 +60,14 @@ public final class HttpUploader HttpURLConnection connection = null; try { - URL url = new URL(mUrl); + URL url = new URL(getUrl()); connection = (HttpURLConnection) url.openConnection(); connection.setConnectTimeout(Constants.CONNECTION_TIMEOUT_MS); connection.setReadTimeout(Constants.READ_TIMEOUT_MS); connection.setUseCaches(false); - connection.setRequestMethod(mMethod); - connection.setDoOutput(mMethod.equals("POST")); - if ("https".equals(connection.getURL().getProtocol()) && mNeedClientAuth) + connection.setRequestMethod(getMethod()); + connection.setDoOutput(getMethod().equals("POST")); + if ("https".equals(connection.getURL().getProtocol()) && needClientAuth()) { HttpsURLConnection httpsConnection = (HttpsURLConnection) connection; String cert = HttpUploader.nativeUserBindingCertificate(); @@ -96,18 +77,18 @@ public final class HttpUploader httpsConnection.setSSLSocketFactory(socketFactory); } - long fileSize = StorageUtils.getFileSize(mFilePath); + long fileSize = StorageUtils.getFileSize(getFilePath()); StringBuilder paramsBuilder = new StringBuilder(); fillBodyParams(paramsBuilder); - File file = new File(mFilePath); - fillFileParams(paramsBuilder, mFileKey, file); + File file = new File(getFilePath()); + fillFileParams(paramsBuilder, getFileKey(), file); int endPartSize = mEndPart.getBytes().length; int paramsSize = paramsBuilder.toString().getBytes().length; long bodyLength = paramsSize + fileSize + endPartSize; setStreamingMode(connection, bodyLength); setHeaders(connection, bodyLength); long startTime = System.currentTimeMillis(); - LOGGER.d(TAG, "Start bookmarks upload on url: '" + Utils.makeUrlSafe(mUrl) + "'"); + LOGGER.d(TAG, "Start bookmarks upload on url: '" + Utils.makeUrlSafe(getUrl()) + "'"); OutputStream outputStream = connection.getOutputStream(); writer = new PrintWriter(new OutputStreamWriter(outputStream, CHARSET)); writeParams(writer, paramsBuilder); @@ -124,7 +105,7 @@ public final class HttpUploader } catch (IOException e) { - message = "I/O exception '" + Utils.makeUrlSafe(mUrl) + "'"; + message = "I/O exception '" + Utils.makeUrlSafe(getUrl()) + "'"; if (connection != null) { String errMsg = readErrorResponse(connection); @@ -201,17 +182,17 @@ public final class HttpUploader private void setHeaders(@NonNull URLConnection connection, long bodyLength) { - mHeaders.add(new KeyValue(HttpClient.HEADER_USER_AGENT, Framework.nativeGetUserAgent())); - mHeaders.add(new KeyValue("App-Version", BuildConfig.VERSION_NAME)); - mHeaders.add(new KeyValue("Content-Type", "multipart/form-data; boundary=" + mBoundary)); - mHeaders.add(new KeyValue("Content-Length", String.valueOf(bodyLength))); - for (KeyValue header : mHeaders) + getHeaders().add(new KeyValue(HttpClient.HEADER_USER_AGENT, Framework.nativeGetUserAgent())); + getHeaders().add(new KeyValue("App-Version", BuildConfig.VERSION_NAME)); + getHeaders().add(new KeyValue("Content-Type", "multipart/form-data; boundary=" + mBoundary)); + getHeaders().add(new KeyValue("Content-Length", String.valueOf(bodyLength))); + for (KeyValue header : getHeaders()) connection.setRequestProperty(header.mKey, header.mValue); } private void fillBodyParams(@NonNull StringBuilder builder) { - for (KeyValue field : mParams) + for (KeyValue field : getParams()) addParam(builder, field.mKey, field.mValue); } diff --git a/platform/http_uploader_background.hpp b/platform/http_uploader_background.hpp index 567a3c8f6f..2d5083cd81 100644 --- a/platform/http_uploader_background.hpp +++ b/platform/http_uploader_background.hpp @@ -12,7 +12,7 @@ public: HttpPayload const & GetPayload() const { return m_payload; } // TODO add platform-specific implementation - void Upload() const {} + void Upload() const; private: HttpPayload m_payload;