summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortobrun <tobrun.van.nuland@gmail.com>2018-07-17 15:05:53 +0200
committerTobrun <tobrun.van.nuland@gmail.com>2018-07-19 11:59:48 +0200
commita7de8580e0e4013f7371b3620c328e1448e58869 (patch)
tree9634d30127609602bb0b7fc0d9d4cc432a7f3a0b
parent5d7e3e24e565afffe2bc9db5029286b167f039ed (diff)
downloadqtlocation-mapboxgl-upstream/tvn-configurable-httpclient.tar.gz
[android] - make used http client configurableupstream/tvn-configurable-httpclient
-rw-r--r--platform/android/MapboxGLAndroidSDK/build.gradle1
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java3
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java273
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequest.java37
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUtil.java10
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/NativeHttpRequest.java75
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/OkHttpRequest.java246
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java18
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java18
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/build.gradle13
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java12
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/render/RenderTestActivity.java24
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/IonHttpRequest.java53
-rw-r--r--platform/android/gradle/dependencies.gradle1
-rw-r--r--platform/android/src/http_file_source.cpp2
15 files changed, 465 insertions, 321 deletions
diff --git a/platform/android/MapboxGLAndroidSDK/build.gradle b/platform/android/MapboxGLAndroidSDK/build.gradle
index 35b4de003b..e3302a7c5a 100644
--- a/platform/android/MapboxGLAndroidSDK/build.gradle
+++ b/platform/android/MapboxGLAndroidSDK/build.gradle
@@ -11,6 +11,7 @@ dependencies {
}
implementation dependenciesList.supportAnnotations
implementation dependenciesList.supportFragmentV4
+ implementation dependenciesList.supportUtilV4
implementation dependenciesList.timber
implementation dependenciesList.okhttp3
testImplementation dependenciesList.junit
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java
index a809460375..14dc60e973 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java
@@ -12,6 +12,7 @@ import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.exceptions.MapboxConfigurationException;
import com.mapbox.mapboxsdk.maps.Telemetry;
import com.mapbox.mapboxsdk.net.ConnectivityReceiver;
+
import timber.log.Timber;
/**
@@ -47,7 +48,7 @@ public final class Mapbox {
Context appContext = context.getApplicationContext();
INSTANCE = new Mapbox(appContext, accessToken);
if (isAccessTokenValid(accessToken)) {
- initializeTelemetry();
+ //initializeTelemetry();
}
ConnectivityReceiver.instance(appContext);
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java
deleted file mode 100644
index e0c63944b9..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java
+++ /dev/null
@@ -1,273 +0,0 @@
-package com.mapbox.mapboxsdk.http;
-
-import android.content.Context;
-import android.content.pm.PackageInfo;
-import android.os.Build;
-import android.support.annotation.NonNull;
-import android.text.TextUtils;
-import android.util.Log;
-import com.mapbox.android.telemetry.TelemetryUtils;
-import com.mapbox.mapboxsdk.BuildConfig;
-import com.mapbox.mapboxsdk.Mapbox;
-import com.mapbox.mapboxsdk.constants.MapboxConstants;
-import okhttp3.Call;
-import okhttp3.Callback;
-import okhttp3.Dispatcher;
-import okhttp3.HttpUrl;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.Response;
-import okhttp3.ResponseBody;
-import timber.log.Timber;
-
-import javax.net.ssl.SSLException;
-import java.io.IOException;
-import java.io.InterruptedIOException;
-import java.net.NoRouteToHostException;
-import java.net.ProtocolException;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-import java.util.concurrent.locks.ReentrantLock;
-
-import static android.util.Log.DEBUG;
-import static android.util.Log.ERROR;
-import static android.util.Log.INFO;
-import static android.util.Log.VERBOSE;
-import static android.util.Log.WARN;
-
-class HTTPRequest implements Callback {
-
- private static final int CONNECTION_ERROR = 0;
- private static final int TEMPORARY_ERROR = 1;
- private static final int PERMANENT_ERROR = 2;
-
- private static OkHttpClient client = new OkHttpClient.Builder().dispatcher(getDispatcher()).build();
- private static boolean logEnabled = true;
- private static boolean logRequestUrl = false;
-
- // Reentrancy is not needed, but "Lock" is an abstract class.
- private ReentrantLock lock = new ReentrantLock();
- private String userAgentString;
- private long nativePtr = 0;
- private Call call;
-
- private HTTPRequest(long nativePtr, String resourceUrl, String etag, String modified) {
- this.nativePtr = nativePtr;
-
- if (resourceUrl.startsWith("local://")) {
- // used by render test to serve files from assets
- executeLocalRequest(resourceUrl);
- return;
- }
- executeRequest(resourceUrl, etag, modified);
- }
-
- public void cancel() {
- // call can be null if the constructor gets aborted (e.g, under a NoRouteToHostException).
- if (call != null) {
- call.cancel();
- }
-
- // TODO: We need a lock here because we can try
- // to cancel at the same time the request is getting
- // answered on the OkHTTP thread. We could get rid of
- // this lock by using Runnable when we move Android
- // implementation of mbgl::RunLoop to Looper.
- lock.lock();
- nativePtr = 0;
- lock.unlock();
- }
-
- @Override
- public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
- if (response.isSuccessful()) {
- log(VERBOSE, String.format("[HTTP] Request was successful (code = %s).", response.code()));
- } else {
- // We don't want to call this unsuccessful because a 304 isn't really an error
- String message = !TextUtils.isEmpty(response.message()) ? response.message() : "No additional information";
- log(DEBUG, String.format("[HTTP] Request with response code = %s: %s", response.code(), message));
- }
-
- ResponseBody responseBody = response.body();
- if (responseBody == null) {
- log(ERROR, "[HTTP] Received empty response body");
- return;
- }
-
- byte[] body;
- try {
- body = responseBody.bytes();
- } catch (IOException ioException) {
- onFailure(call, ioException);
- // throw ioException;
- return;
- } finally {
- response.close();
- }
-
- lock.lock();
- if (nativePtr != 0) {
- nativeOnResponse(response.code(),
- response.header("ETag"),
- response.header("Last-Modified"),
- response.header("Cache-Control"),
- response.header("Expires"),
- response.header("Retry-After"),
- response.header("x-rate-limit-reset"),
- body);
- }
- lock.unlock();
- }
-
- @Override
- public void onFailure(@NonNull Call call, @NonNull IOException e) {
- handleFailure(call, e);
- }
-
- static void enableLog(boolean enabled) {
- logEnabled = enabled;
- }
-
- static void enablePrintRequestUrlOnFailure(boolean enabled) {
- logRequestUrl = enabled;
- }
-
- static void setOKHttpClient(OkHttpClient client) {
- HTTPRequest.client = client;
- }
-
- private static Dispatcher getDispatcher() {
- Dispatcher dispatcher = new Dispatcher();
- // Matches core limit set on
- // https://github.com/mapbox/mapbox-gl-native/blob/master/platform/android/src/http_file_source.cpp#L192
- dispatcher.setMaxRequestsPerHost(20);
- return dispatcher;
- }
-
- private void executeRequest(String resourceUrl, String etag, String modified) {
- try {
- HttpUrl httpUrl = HttpUrl.parse(resourceUrl);
- if (httpUrl == null) {
- log(Log.ERROR, String.format("[HTTP] Unable to parse resourceUrl %s", resourceUrl));
- }
-
- final String host = httpUrl.host().toLowerCase(MapboxConstants.MAPBOX_LOCALE);
- // Don't try a request to remote server if we aren't connected
- if (!Mapbox.isConnected() && !host.equals("127.0.0.1") && !host.equals("localhost")) {
- throw new NoRouteToHostException("No Internet connection available.");
- }
-
- if (host.equals("mapbox.com") || host.endsWith(".mapbox.com") || host.equals("mapbox.cn")
- || host.endsWith(".mapbox.cn")) {
- if (httpUrl.querySize() == 0) {
- resourceUrl = resourceUrl + "?";
- } else {
- resourceUrl = resourceUrl + "&";
- }
- resourceUrl = resourceUrl + "events=true";
- }
-
- Request.Builder builder = new Request.Builder()
- .url(resourceUrl)
- .tag(resourceUrl.toLowerCase(MapboxConstants.MAPBOX_LOCALE))
- .addHeader("User-Agent", getUserAgent());
- if (etag.length() > 0) {
- builder = builder.addHeader("If-None-Match", etag);
- } else if (modified.length() > 0) {
- builder = builder.addHeader("If-Modified-Since", modified);
- }
- Request request = builder.build();
- call = client.newCall(request);
- call.enqueue(this);
- } catch (Exception exception) {
- handleFailure(call, exception);
- }
- }
-
- private void executeLocalRequest(String resourceUrl) {
- new LocalRequestTask(new LocalRequestTask.OnLocalRequestResponse() {
- @Override
- public void onResponse(byte[] bytes) {
- if (bytes != null) {
- lock.lock();
- if (nativePtr != 0) {
- nativeOnResponse(200, null, null, null, null, null, null, bytes);
- }
- lock.unlock();
- }
- }
- }).execute(resourceUrl);
- }
-
- private void handleFailure(Call call, Exception e) {
- String errorMessage = e.getMessage() != null ? e.getMessage() : "Error processing the request";
- int type = getFailureType(e);
-
- if (logEnabled && call != null && call.request() != null) {
- String requestUrl = call.request().url().toString();
- logFailure(type, errorMessage, requestUrl);
- }
-
- lock.lock();
- if (nativePtr != 0) {
- nativeOnFailure(type, errorMessage);
- }
- lock.unlock();
- }
-
- private int getFailureType(Exception e) {
- if ((e instanceof NoRouteToHostException) || (e instanceof UnknownHostException) || (e instanceof SocketException)
- || (e instanceof ProtocolException) || (e instanceof SSLException)) {
- return CONNECTION_ERROR;
- } else if ((e instanceof InterruptedIOException)) {
- return TEMPORARY_ERROR;
- }
- return PERMANENT_ERROR;
- }
-
- private void log(int type, String errorMessage) {
- if (logEnabled) {
- Timber.log(type, errorMessage);
- }
- }
-
- private void logFailure(int type, String errorMessage, String requestUrl) {
- log(type == TEMPORARY_ERROR ? DEBUG : type == CONNECTION_ERROR ? INFO : WARN,
- String.format(
- "Request failed due to a %s error: %s %s",
- type == TEMPORARY_ERROR ? "temporary" : type == CONNECTION_ERROR ? "connection" : "permanent",
- errorMessage,
- logRequestUrl ? requestUrl : ""
- )
- );
- }
-
- private String getUserAgent() {
- if (userAgentString == null) {
- userAgentString = TelemetryUtils.toHumanReadableAscii(
- String.format("%s %s (%s) Android/%s (%s)",
- getApplicationIdentifier(),
- BuildConfig.MAPBOX_VERSION_STRING,
- BuildConfig.GIT_REVISION_SHORT,
- Build.VERSION.SDK_INT,
- Build.CPU_ABI)
- );
- }
- return userAgentString;
- }
-
- private String getApplicationIdentifier() {
- try {
- Context context = Mapbox.getApplicationContext();
- PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
- return String.format("%s/%s (%s)", context.getPackageName(), packageInfo.versionName, packageInfo.versionCode);
- } catch (Exception exception) {
- return "";
- }
- }
-
- private native void nativeOnFailure(int type, String message);
-
- private native void nativeOnResponse(int code, String etag, String modified, String cacheControl, String expires,
- String retryAfter, String xRateLimitReset, byte[] body);
-}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequest.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequest.java
new file mode 100644
index 0000000000..f39a92f07c
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequest.java
@@ -0,0 +1,37 @@
+package com.mapbox.mapboxsdk.http;
+
+import android.support.annotation.Nullable;
+
+public abstract class HttpRequest {
+
+ private static HttpRequest httpRequest;
+
+ static final int CONNECTION_ERROR = 0;
+ static final int TEMPORARY_ERROR = 1;
+ static final int PERMANENT_ERROR = 2;
+
+ public static synchronized void setHttpRequest(@Nullable HttpRequest requestImpl) {
+ httpRequest = requestImpl;
+ }
+
+ public abstract void executeRequest(NativeHttpRequest httpRequest, long nativePtr, String resourceUrl,
+ String etag, String modified);
+
+ public abstract void cancelRequest(long nativePtr);
+
+ static void execute(NativeHttpRequest httpRequest, long nativePtr, String resourceUrl,
+ String etag, String modified) {
+ getInstance().executeRequest(httpRequest, nativePtr, resourceUrl, etag, modified);
+ }
+
+ static void cancel(long nativePtr) {
+ getInstance().cancelRequest(nativePtr);
+ }
+
+ private static synchronized HttpRequest getInstance() {
+ if (httpRequest == null) {
+ httpRequest = new OkHttpRequest();
+ }
+ return httpRequest;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUtil.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUtil.java
index 872032867a..a8580c6105 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUtil.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUtil.java
@@ -3,12 +3,12 @@ package com.mapbox.mapboxsdk.http;
import okhttp3.OkHttpClient;
/**
- * Utility class for setting HttpRequest configurations
+ * Utility class for setting OkHttpRequest configurations
*/
public class HttpRequestUtil {
/**
- * Set the log state of HttpRequest. Default value is true.
+ * Set the log state of OkHttpRequest. Default value is true.
* <p>
* This configuration will outlast the lifecycle of the Map.
* </p>
@@ -16,7 +16,7 @@ public class HttpRequestUtil {
* @param enabled True will enable logging, false will disable
*/
public static void setLogEnabled(boolean enabled) {
- HTTPRequest.enableLog(enabled);
+ OkHttpRequest.enableLog(enabled);
}
/**
@@ -31,7 +31,7 @@ public class HttpRequestUtil {
* @param enabled True will print urls, false will disable
*/
public static void setPrintRequestUrlOnFailure(boolean enabled) {
- HTTPRequest.enablePrintRequestUrlOnFailure(enabled);
+ OkHttpRequest.enablePrintRequestUrlOnFailure(enabled);
}
/**
@@ -40,7 +40,7 @@ public class HttpRequestUtil {
* @param client the OkHttpClient
*/
public static void setOkHttpClient(OkHttpClient client) {
- HTTPRequest.setOKHttpClient(client);
+ OkHttpRequest.setOkHttpClient(client);
}
} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/NativeHttpRequest.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/NativeHttpRequest.java
new file mode 100644
index 0000000000..93d5d1d33e
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/NativeHttpRequest.java
@@ -0,0 +1,75 @@
+package com.mapbox.mapboxsdk.http;
+
+import java.util.concurrent.locks.ReentrantLock;
+
+public class NativeHttpRequest {
+
+ // Reentrancy is not needed, but "Lock" is an abstract class.
+ private ReentrantLock lock = new ReentrantLock();
+ private long nativePtr = 0;
+
+ private NativeHttpRequest(long nativePtr, String resourceUrl, String etag, String modified) {
+ this.nativePtr = nativePtr;
+
+ if (resourceUrl.startsWith("local://")) {
+ // used by render test to serve files from assets
+ executeLocalRequest(resourceUrl);
+ return;
+ }
+ HttpRequest.execute(this, nativePtr, resourceUrl, etag, modified);
+ }
+
+ public void cancel() {
+ HttpRequest.cancel(nativePtr);
+
+ // TODO: We need a lock here because we can try
+ // to cancel at the same time the request is getting
+ // answered on the OkHTTP thread. We could get rid of
+ // this lock by using Runnable when we move Android
+ // implementation of mbgl::RunLoop to Looper.
+ lock.lock();
+ nativePtr = 0;
+ lock.unlock();
+ }
+
+ public void onResponse(int responseCode, String etag, String lastModified, String cacheControl, String expires,
+ String retryAfter, String xRateLimitReset, byte[] body) {
+ lock.lock();
+ if (nativePtr != 0) {
+ nativeOnResponse(responseCode,
+ etag,
+ lastModified,
+ cacheControl,
+ expires,
+ retryAfter,
+ xRateLimitReset,
+ body);
+ }
+ lock.unlock();
+ }
+
+ private void executeLocalRequest(String resourceUrl) {
+ new LocalRequestTask(bytes -> {
+ if (bytes != null) {
+ lock.lock();
+ if (nativePtr != 0) {
+ nativeOnResponse(200, null, null, null, null, null, null, bytes);
+ }
+ lock.unlock();
+ }
+ }).execute(resourceUrl);
+ }
+
+ public void handleFailure(int type, String errorMessage) {
+ lock.lock();
+ if (nativePtr != 0) {
+ nativeOnFailure(type, errorMessage);
+ }
+ lock.unlock();
+ }
+
+ private native void nativeOnFailure(int type, String message);
+
+ private native void nativeOnResponse(int code, String etag, String modified, String cacheControl, String expires,
+ String retryAfter, String xRateLimitReset, byte[] body);
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/OkHttpRequest.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/OkHttpRequest.java
new file mode 100644
index 0000000000..182ab90e0b
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/OkHttpRequest.java
@@ -0,0 +1,246 @@
+package com.mapbox.mapboxsdk.http;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.os.Build;
+import android.support.annotation.NonNull;
+import android.support.v4.util.LongSparseArray;
+import android.text.TextUtils;
+import android.util.Log;
+import com.mapbox.android.telemetry.TelemetryUtils;
+import com.mapbox.mapboxsdk.BuildConfig;
+import com.mapbox.mapboxsdk.Mapbox;
+import com.mapbox.mapboxsdk.constants.MapboxConstants;
+import okhttp3.Call;
+import okhttp3.Callback;
+import okhttp3.Dispatcher;
+import okhttp3.HttpUrl;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+import okhttp3.ResponseBody;
+import timber.log.Timber;
+
+import javax.net.ssl.SSLException;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.NoRouteToHostException;
+import java.net.ProtocolException;
+import java.net.SocketException;
+import java.net.UnknownHostException;
+
+public class OkHttpRequest extends HttpRequest {
+
+ private static final LongSparseArray<Call> calls = new LongSparseArray<>();
+ private static final String userAgentString = TelemetryUtils.toHumanReadableAscii(
+ String.format("%s %s (%s) Android/%s (%s)",
+ getApplicationIdentifier(),
+ BuildConfig.MAPBOX_VERSION_STRING,
+ BuildConfig.GIT_REVISION_SHORT,
+ Build.VERSION.SDK_INT,
+ Build.CPU_ABI)
+ );
+
+ private static OkHttpClient client = new OkHttpClient.Builder().dispatcher(getDispatcher()).build();
+ private static boolean logEnabled = true;
+ private static boolean logRequestUrl = false;
+
+ @Override
+ public void executeRequest(NativeHttpRequest httpRequest, long nativePtr, String resourceUrl,
+ String etag, String modified) {
+ Call call = null;
+ OkHttpCallback callback = new OkHttpCallback(httpRequest);
+ try {
+ HttpUrl httpUrl = HttpUrl.parse(resourceUrl);
+ if (httpUrl == null) {
+ log(Log.ERROR, String.format("[HTTP] Unable to parse resourceUrl %s", resourceUrl));
+ }
+
+ final String host = httpUrl.host().toLowerCase(MapboxConstants.MAPBOX_LOCALE);
+ // Don't try a request to remote server if we aren't connected
+ if (!Mapbox.isConnected() && !host.equals("127.0.0.1") && !host.equals("localhost")) {
+ throw new NoRouteToHostException("No Internet connection available.");
+ }
+
+ if (host.equals("mapbox.com") || host.endsWith(".mapbox.com") || host.equals("mapbox.cn")
+ || host.endsWith(".mapbox.cn")) {
+ if (httpUrl.querySize() == 0) {
+ resourceUrl = resourceUrl + "?";
+ } else {
+ resourceUrl = resourceUrl + "&";
+ }
+ resourceUrl = resourceUrl + "events=true";
+ }
+
+ Request.Builder builder = new Request.Builder()
+ .url(resourceUrl)
+ .tag(resourceUrl.toLowerCase(MapboxConstants.MAPBOX_LOCALE))
+ .addHeader("User-Agent", userAgentString);
+ if (etag.length() > 0) {
+ builder = builder.addHeader("If-None-Match", etag);
+ } else if (modified.length() > 0) {
+ builder = builder.addHeader("If-Modified-Since", modified);
+ }
+ Request request = builder.build();
+ call = client.newCall(request);
+
+ synchronized (calls) {
+ calls.put(nativePtr, call);
+ }
+
+ call.enqueue(callback);
+ Timber.e("Requesting resource with size %s for %s", calls.size(), call.hashCode());
+ } catch (Exception exception) {
+ callback.handleFailure(call, exception);
+ }
+ }
+
+ @Override
+ public void cancelRequest(long nativePtr) {
+ synchronized (calls) {
+ Call call = calls.get(nativePtr);
+ // call can be null if the constructor gets aborted (e.g, under a NoRouteToHostException).
+ if (call != null) {
+ call.cancel();
+ calls.delete(nativePtr);
+ }
+ }
+ }
+
+ public static void enablePrintRequestUrlOnFailure(boolean enabled) {
+ logRequestUrl = enabled;
+ }
+
+ public static void enableLog(boolean enabled) {
+ logEnabled = enabled;
+ }
+
+ public static void setOkHttpClient(OkHttpClient okHttpClient) {
+ OkHttpRequest.client = okHttpClient;
+ }
+
+ private static class OkHttpCallback implements Callback {
+
+ private NativeHttpRequest httpRequest;
+
+ OkHttpCallback(NativeHttpRequest httpRequest) {
+ this.httpRequest = httpRequest;
+ }
+
+ @Override
+ public void onFailure(@NonNull Call call, @NonNull IOException e) {
+ handleFailure(call, e);
+ }
+
+ @Override
+ public void onResponse(@NonNull Call call, @NonNull Response response) {
+ if (response.isSuccessful()) {
+ log(Log.VERBOSE, String.format("[HTTP] Request was successful (code = %s).", response.code()));
+ } else {
+ // We don't want to call this unsuccessful because a 304 isn't really an error
+ String message = !TextUtils.isEmpty(response.message()) ? response.message() : "No additional information";
+ log(Log.DEBUG, String.format("[HTTP] Request with response code = %s: %s", response.code(), message));
+ }
+
+ removeCall(call);
+
+ ResponseBody responseBody = response.body();
+ if (responseBody == null) {
+ log(Log.ERROR, "[HTTP] Received empty response body");
+ return;
+ }
+
+ byte[] body;
+ try {
+ body = responseBody.bytes();
+ } catch (IOException ioException) {
+ onFailure(call, ioException);
+ // throw ioException;
+ return;
+ } finally {
+ response.close();
+ }
+
+ httpRequest.onResponse(response.code(),
+ response.header("ETag"),
+ response.header("Last-Modified"),
+ response.header("Cache-Control"),
+ response.header("Expires"),
+ response.header("Retry-After"),
+ response.header("x-rate-limit-reset"),
+ body);
+ }
+
+ private void handleFailure(Call call, Exception e) {
+ String errorMessage = e.getMessage() != null ? e.getMessage() : "Error processing the request";
+ int type = getFailureType(e);
+
+ if (logEnabled && call != null && call.request() != null) {
+ String requestUrl = call.request().url().toString();
+ logFailure(type, errorMessage, requestUrl);
+ }
+
+ removeCall(call);
+ Timber.e("Handle Failure with size %s for %s", calls.size(), call.hashCode());
+ httpRequest.handleFailure(type, errorMessage);
+ }
+
+ private void logFailure(int type, String errorMessage, String requestUrl) {
+ log(type == TEMPORARY_ERROR ? Log.DEBUG : type == CONNECTION_ERROR ? Log.INFO : Log.WARN,
+ String.format(
+ "Request failed due to a %s error: %s %s",
+ type == TEMPORARY_ERROR ? "temporary" : type == CONNECTION_ERROR ? "connection" : "permanent",
+ errorMessage,
+ logRequestUrl ? requestUrl : ""
+ )
+ );
+ }
+
+ private int getFailureType(Exception e) {
+ if ((e instanceof NoRouteToHostException) || (e instanceof UnknownHostException) || (e instanceof SocketException)
+ || (e instanceof ProtocolException) || (e instanceof SSLException)) {
+ return CONNECTION_ERROR;
+ } else if ((e instanceof InterruptedIOException)) {
+ return TEMPORARY_ERROR;
+ }
+ return PERMANENT_ERROR;
+ }
+
+ private void removeCall(Call call) {
+ synchronized (calls) {
+ Call currentCall;
+ for (int i = 0; i < calls.size(); i++) {
+ currentCall = calls.valueAt(i);
+ if (call.equals(currentCall)) {
+ calls.delete(calls.keyAt(i));
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ private static String getApplicationIdentifier() {
+ try {
+ Context context = Mapbox.getApplicationContext();
+ PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
+ return String.format("%s/%s (%s)", context.getPackageName(), packageInfo.versionName, packageInfo.versionCode);
+ } catch (Exception exception) {
+ return "";
+ }
+ }
+
+ private static Dispatcher getDispatcher() {
+ Dispatcher dispatcher = new Dispatcher();
+ // Matches core limit set on
+ // https://github.com/mapbox/mapbox-gl-native/blob/master/platform/android/src/http_file_source.cpp#L192
+ dispatcher.setMaxRequestsPerHost(20);
+ return dispatcher;
+ }
+
+ static void log(int type, String errorMessage) {
+ if (logEnabled) {
+ Timber.log(type, errorMessage);
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java
index fc4b13a293..ff9909ef8a 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java
@@ -19,14 +19,10 @@ import com.mapbox.android.gestures.RotateGestureDetector;
import com.mapbox.android.gestures.ShoveGestureDetector;
import com.mapbox.android.gestures.StandardGestureDetector;
import com.mapbox.android.gestures.StandardScaleGestureDetector;
-import com.mapbox.android.telemetry.Event;
-import com.mapbox.android.telemetry.MapEventFactory;
-import com.mapbox.android.telemetry.MapState;
-import com.mapbox.android.telemetry.MapboxTelemetry;
+
import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
-import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.utils.MathUtils;
import java.util.ArrayList;
@@ -887,12 +883,12 @@ final class MapGestureDetector {
if (cameraPosition != null) {
double zoom = cameraPosition.zoom;
if (isZoomValid(zoom)) {
- MapboxTelemetry telemetry = Telemetry.obtainTelemetry();
- MapEventFactory mapEventFactory = new MapEventFactory();
- LatLng latLng = projection.fromScreenLocation(focalPoint);
- MapState state = new MapState(latLng.getLatitude(), latLng.getLongitude(), zoom);
- state.setGesture(eventType);
- telemetry.push(mapEventFactory.createMapGestureEvent(Event.Type.MAP_CLICK, state));
+ //MapboxTelemetry telemetry = Telemetry.obtainTelemetry();
+ //MapEventFactory mapEventFactory = new MapEventFactory();
+ //LatLng latLng = projection.fromScreenLocation(focalPoint);
+ //MapState state = new MapState(latLng.getLatitude(), latLng.getLongitude(), zoom);
+ //state.setGesture(eventType);
+ //telemetry.push(mapEventFactory.createMapGestureEvent(Event.Type.MAP_CLICK, state));
}
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
index 0fa1072cd2..f70f0e5039 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
@@ -24,11 +24,7 @@ import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.ZoomButtonsController;
import com.mapbox.android.gestures.AndroidGesturesManager;
-import com.mapbox.android.telemetry.AppUserTurnstile;
-import com.mapbox.android.telemetry.Event;
-import com.mapbox.android.telemetry.MapEventFactory;
-import com.mapbox.android.telemetry.MapboxTelemetry;
-import com.mapbox.mapboxsdk.BuildConfig;
+
import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.annotations.Annotation;
import com.mapbox.mapboxsdk.annotations.MarkerViewManager;
@@ -271,12 +267,12 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback {
@UiThread
public void onCreate(@Nullable Bundle savedInstanceState) {
if (savedInstanceState == null) {
- MapboxTelemetry telemetry = Telemetry.obtainTelemetry();
- AppUserTurnstile turnstileEvent = new AppUserTurnstile(BuildConfig.MAPBOX_SDK_IDENTIFIER,
- BuildConfig.MAPBOX_SDK_VERSION);
- telemetry.push(turnstileEvent);
- MapEventFactory mapEventFactory = new MapEventFactory();
- telemetry.push(mapEventFactory.createMapLoadEvent(Event.Type.MAP_LOAD));
+ // MapboxTelemetry telemetry = Telemetry.obtainTelemetry();
+ // AppUserTurnstile turnstileEvent = new AppUserTurnstile(BuildConfig.MAPBOX_SDK_IDENTIFIER,
+ // BuildConfig.MAPBOX_SDK_VERSION);
+ // telemetry.push(turnstileEvent);
+ // MapEventFactory mapEventFactory = new MapEventFactory();
+ // telemetry.push(mapEventFactory.createMapLoadEvent(Event.Type.MAP_LOAD));
} else if (savedInstanceState.getBoolean(MapboxConstants.STATE_HAS_SAVED_STATE)) {
this.savedInstanceState = savedInstanceState;
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
index d21eb73382..c5dcd5e88c 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
+++ b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
@@ -54,10 +54,17 @@ android {
dependencies {
implementation dependenciesList.kotlinLib
- api(project(':MapboxGLAndroidSDK'))
- implementation dependenciesList.mapboxJavaServices
- implementation dependenciesList.mapboxJavaTurf
+ api(project(':MapboxGLAndroidSDK')) {
+ exclude group: 'com.squareup.okhttp3', module: 'okhttp'
+ }
+
+ implementation(dependenciesList.mapboxJavaTurf) {
+ exclude group: 'com.squareup.okhttp3', module: 'okhttp'
+ exclude group: 'com.squareup.okhttp3', module: 'logging-interceptor'
+ }
+
+ implementation 'com.koushikdutta.ion:ion:2.2.1'
implementation dependenciesList.supportAppcompatV7
implementation dependenciesList.supportRecyclerView
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java
index a06a489388..6313eddc5b 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java
@@ -3,10 +3,13 @@ package com.mapbox.mapboxsdk.testapp;
import android.app.Application;
import android.os.StrictMode;
import android.text.TextUtils;
+
import com.mapbox.mapboxsdk.Mapbox;
-import com.mapbox.mapboxsdk.maps.Telemetry;
+import com.mapbox.mapboxsdk.http.HttpRequest;
+import com.mapbox.mapboxsdk.testapp.utils.IonHttpRequest;
import com.mapbox.mapboxsdk.testapp.utils.TokenUtils;
import com.squareup.leakcanary.LeakCanary;
+
import timber.log.Timber;
import static timber.log.Timber.DebugTree;
@@ -31,11 +34,16 @@ public class MapboxApplication extends Application {
if (!initializeLeakCanary()) {
return;
}
+ initializeHttpClient();
initializeLogger();
initializeStrictMode();
initializeMapbox();
}
+ private void initializeHttpClient() {
+ HttpRequest.setHttpRequest(new IonHttpRequest(this));
+ }
+
private boolean initializeLeakCanary() {
if (LeakCanary.isInAnalyzerProcess(this)) {
// This process is dedicated to LeakCanary for heap analysis.
@@ -70,7 +78,7 @@ public class MapboxApplication extends Application {
String accessToken = TokenUtils.getMapboxAccessToken(getApplicationContext());
validateAccessToken(accessToken);
Mapbox.getInstance(getApplicationContext(), accessToken);
- Telemetry.updateDebugLoggingEnabled(true);
+ //Telemetry.updateDebugLoggingEnabled(true);
}
private static void validateAccessToken(String accessToken) {
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/render/RenderTestActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/render/RenderTestActivity.java
index e3c5254805..6c37f3d5ea 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/render/RenderTestActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/render/RenderTestActivity.java
@@ -12,11 +12,8 @@ import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import com.google.gson.Gson;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
import com.mapbox.mapboxsdk.snapshotter.MapSnapshotter;
-import okio.BufferedSource;
-import okio.Okio;
+
import timber.log.Timber;
import java.io.File;
@@ -24,7 +21,6 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
-import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -167,13 +163,13 @@ public class RenderTestActivity extends AppCompatActivity {
private static List<String> loadIgnoreList(AssetManager assets) {
List<String> ignores = new ArrayList<>();
try (InputStream input = assets.open(String.format("%s/ignores.json", TEST_BASE_PATH))) {
- BufferedSource source = Okio.buffer(Okio.source(input));
- String styleJson = source.readByteString().string(Charset.forName("utf-8"));
- JsonObject object = new Gson().fromJson(styleJson, JsonObject.class);
- for (Map.Entry<String, JsonElement> stringJsonElementEntry : object.entrySet()) {
- String[] parts = stringJsonElementEntry.getKey().split("/");
- ignores.add(String.format("%s,%s", parts[2], parts[1]));
- }
+ // BufferedSource source = Okio.buffer(Okio.source(input));
+ // String styleJson = source.readByteString().string(Charset.forName("utf-8"));
+ // JsonObject object = new Gson().fromJson(styleJson, JsonObject.class);
+ // for (Map.Entry<String, JsonElement> stringJsonElementEntry : object.entrySet()) {
+ // String[] parts = stringJsonElementEntry.getKey().split("/");
+ // ignores.add(String.format("%s,%s", parts[2], parts[1]));
+ // }
} catch (IOException exception) {
Timber.e(exception);
}
@@ -183,8 +179,8 @@ public class RenderTestActivity extends AppCompatActivity {
private static String loadStyleJson(AssetManager assets, String category, String test) {
String styleJson = null;
try (InputStream input = assets.open(String.format("%s/%s/%s/style.json", RENDER_TEST_BASE_PATH, category, test))) {
- BufferedSource source = Okio.buffer(Okio.source(input));
- styleJson = source.readByteString().string(Charset.forName("utf-8"));
+ // BufferedSource source = Okio.buffer(Okio.source(input));
+ // styleJson = source.readByteString().string(Charset.forName("utf-8"));
} catch (IOException exception) {
Timber.e(exception);
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/IonHttpRequest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/IonHttpRequest.java
new file mode 100644
index 0000000000..d4fa8b547e
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/IonHttpRequest.java
@@ -0,0 +1,53 @@
+package com.mapbox.mapboxsdk.testapp.utils;
+
+import android.content.Context;
+
+import com.koushikdutta.ion.Ion;
+import com.koushikdutta.ion.Response;
+import com.koushikdutta.ion.builder.Builders;
+import com.mapbox.mapboxsdk.http.HttpRequest;
+import com.mapbox.mapboxsdk.http.NativeHttpRequest;
+
+import java.lang.ref.WeakReference;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+public class IonHttpRequest extends HttpRequest {
+
+ private WeakReference<Context> context;
+
+ public IonHttpRequest(Context context) {
+ this.context = new WeakReference<>(context);
+ }
+
+ @Override
+ public void executeRequest(NativeHttpRequest httpRequest, long nativePtr, String resourceUrl,
+ String etag, String modified) {
+ Context context = this.context.get();
+ if (context != null) {
+ Builders.Any.B loadBuilder = Ion.with(context).load(resourceUrl);
+ if (etag.length() > 0) {
+ loadBuilder.addHeader("If-None-Match", etag);
+ } else if (modified.length() > 0) {
+ loadBuilder.addHeader("If-Modified-Since", modified);
+ }
+ Future<Response<byte[]>> future = loadBuilder.asByteArray().withResponse();
+ try {
+ Response<byte[]> result = future.get();
+ int statusCode = result.getHeaders().code();
+ httpRequest.onResponse(statusCode, null, null, null, null, null, null, result.getResult());
+ } catch (InterruptedException interruptedException) {
+ interruptedException.printStackTrace();
+ } catch (ExecutionException executionException) {
+ executionException.printStackTrace();
+ }
+ }
+ }
+
+ @Override
+ public void cancelRequest(long nativePtr) {
+ // do nothing
+ // TODO manage Future objects and execute Future#cancel
+ }
+
+}
diff --git a/platform/android/gradle/dependencies.gradle b/platform/android/gradle/dependencies.gradle
index fccaea9f71..01b92fe1c6 100644
--- a/platform/android/gradle/dependencies.gradle
+++ b/platform/android/gradle/dependencies.gradle
@@ -46,6 +46,7 @@ ext {
supportAnnotations : "com.android.support:support-annotations:${versions.supportLib}",
supportAppcompatV7 : "com.android.support:appcompat-v7:${versions.supportLib}",
supportFragmentV4 : "com.android.support:support-fragment:${versions.supportLib}",
+ supportUtilV4 : "com.android.support:support-core-utils:${versions.supportLib}",
supportDesign : "com.android.support:design:${versions.supportLib}",
supportRecyclerView : "com.android.support:recyclerview-v7:${versions.supportLib}",
diff --git a/platform/android/src/http_file_source.cpp b/platform/android/src/http_file_source.cpp
index cda84209ea..fc7ffbec8c 100644
--- a/platform/android/src/http_file_source.cpp
+++ b/platform/android/src/http_file_source.cpp
@@ -20,7 +20,7 @@ public:
class HTTPRequest : public AsyncRequest {
public:
- static constexpr auto Name() { return "com/mapbox/mapboxsdk/http/HTTPRequest"; };
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/http/NativeHttpRequest"; };
HTTPRequest(jni::JNIEnv&, const Resource&, FileSource::Callback);
~HTTPRequest();