summaryrefslogtreecommitdiff
path: root/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http
diff options
context:
space:
mode:
Diffstat (limited to 'platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http')
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java279
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpIdentifier.java36
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpLogger.java35
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequest.java31
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUrl.java40
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUtil.java19
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpResponder.java32
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/LocalRequestTask.java6
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/NativeHttpRequest.java85
9 files changed, 277 insertions, 286 deletions
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 9e3056bf8e..0000000000
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java
+++ /dev/null
@@ -1,279 +0,0 @@
-package com.mapbox.mapboxsdk.http;
-
-import android.content.Context;
-import android.content.pm.PackageInfo;
-import android.os.Build;
-import android.support.annotation.Keep;
-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;
- @Keep
- private long nativePtr = 0;
- private Call call;
-
- @Keep
- 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);
- }
-
- @Keep
- 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 "";
- }
- }
-
- @Keep
- private native void nativeOnFailure(int type, String message);
-
- @Keep
- 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/HttpIdentifier.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpIdentifier.java
new file mode 100644
index 0000000000..d50be55878
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpIdentifier.java
@@ -0,0 +1,36 @@
+package com.mapbox.mapboxsdk.http;
+
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.support.annotation.NonNull;
+import com.mapbox.mapboxsdk.Mapbox;
+
+public class HttpIdentifier {
+
+ private HttpIdentifier() {
+ }
+
+ /**
+ * Returns the application identifier, consisting out the package name, version name and version code.
+ *
+ * @return the application identifier
+ */
+ public static String getIdentifier() {
+ return getIdentifier(Mapbox.getApplicationContext());
+ }
+
+ /**
+ * Returns the application identifier, consisting out the package name, version name and version code.
+ *
+ * @param context the context used to retrieve the package manager from
+ * @return the application identifier
+ */
+ private static String getIdentifier(@NonNull Context context) {
+ try {
+ PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
+ return String.format("%s/%s (%s)", context.getPackageName(), packageInfo.versionName, packageInfo.versionCode);
+ } catch (Exception exception) {
+ return "";
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpLogger.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpLogger.java
new file mode 100644
index 0000000000..2f44694f0c
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpLogger.java
@@ -0,0 +1,35 @@
+package com.mapbox.mapboxsdk.http;
+
+import android.util.Log;
+import com.mapbox.mapboxsdk.log.Logger;
+
+import static com.mapbox.mapboxsdk.http.HttpRequest.CONNECTION_ERROR;
+import static com.mapbox.mapboxsdk.http.HttpRequest.TEMPORARY_ERROR;
+
+public class HttpLogger {
+
+ private static final String TAG = "Mbgl-HttpRequest";
+
+ public static boolean logRequestUrl;
+ public static boolean logEnabled = true;
+
+ private HttpLogger(){
+ }
+
+ public static 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 : ""
+ )
+ );
+ }
+
+ public static void log(int type, String errorMessage) {
+ if (logEnabled) {
+ Logger.log(type, TAG, errorMessage);
+ }
+ }
+}
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..fdbb589fef
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequest.java
@@ -0,0 +1,31 @@
+package com.mapbox.mapboxsdk.http;
+
+/**
+ * Interface definition for performing http requests.
+ * <p>
+ * This allows to provide alternative implementations for the http interaction of this library.
+ * </p>
+ */
+public interface HttpRequest {
+
+ int CONNECTION_ERROR = 0;
+ int TEMPORARY_ERROR = 1;
+ int PERMANENT_ERROR = 2;
+
+ /**
+ * Executes the request.
+ *
+ * @param httpRequest callback to be invoked when we receive a response
+ * @param nativePtr the pointer associated to the request
+ * @param resourceUrl the resource url to download
+ * @param etag http header, identifier for a specific version of a resource
+ * @param modified http header, used to determine if a resource hasn't been modified since
+ */
+ void executeRequest(HttpResponder httpRequest, long nativePtr, String resourceUrl,
+ String etag, String modified);
+
+ /**
+ * Cancels the request.
+ */
+ void cancelRequest();
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUrl.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUrl.java
new file mode 100644
index 0000000000..fde8ae4a5d
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUrl.java
@@ -0,0 +1,40 @@
+package com.mapbox.mapboxsdk.http;
+
+public class HttpRequestUrl {
+
+ private HttpRequestUrl() {
+ }
+
+ /**
+ * Adapts a resource request url based on the host and query size.
+ *
+ * @param host the host used as endpoint
+ * @param resourceUrl the resource to download
+ * @param querySize the query size of the resource request
+ * @return the adapted resource url
+ */
+ public static String buildResourceUrl(String host, String resourceUrl, int querySize) {
+ if (isValidMapboxEndpoint(host)) {
+ if (querySize == 0) {
+ resourceUrl = resourceUrl + "?";
+ } else {
+ resourceUrl = resourceUrl + "&";
+ }
+ resourceUrl = resourceUrl + "events=true";
+ }
+ return resourceUrl;
+ }
+
+ /**
+ * Validates if the host used as endpoint is a valid Mapbox endpoint.
+ *
+ * @param host the host used as endpoint
+ * @return true if a valid Mapbox endpoint
+ */
+ private static boolean isValidMapboxEndpoint(String host) {
+ return host.equals("mapbox.com")
+ || host.endsWith(".mapbox.com")
+ || host.equals("mapbox.cn")
+ || host.endsWith(".mapbox.cn");
+ }
+}
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..2b85555cc7 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,8 +3,11 @@ package com.mapbox.mapboxsdk.http;
import okhttp3.OkHttpClient;
/**
- * Utility class for setting HttpRequest configurations
+ * Utility class for setting HttpRequest configurations.
+ *
+ * @deprecated use {@link com.mapbox.mapboxsdk.module.http.HttpRequestUtil} instead
*/
+@Deprecated
public class HttpRequestUtil {
/**
@@ -14,9 +17,11 @@ public class HttpRequestUtil {
* </p>
*
* @param enabled True will enable logging, false will disable
+ * @deprecated use {@link com.mapbox.mapboxsdk.module.http.HttpRequestUtil#setLogEnabled(boolean)} instead
*/
+ @Deprecated
public static void setLogEnabled(boolean enabled) {
- HTTPRequest.enableLog(enabled);
+ com.mapbox.mapboxsdk.module.http.HttpRequestUtil.setLogEnabled(enabled);
}
/**
@@ -29,18 +34,22 @@ public class HttpRequestUtil {
* </p>
*
* @param enabled True will print urls, false will disable
+ * @deprecated use {@link com.mapbox.mapboxsdk.module.http.HttpRequestUtil#setPrintRequestUrlOnFailure(boolean)}
+ * instead
*/
+ @Deprecated
public static void setPrintRequestUrlOnFailure(boolean enabled) {
- HTTPRequest.enablePrintRequestUrlOnFailure(enabled);
+ com.mapbox.mapboxsdk.module.http.HttpRequestUtil.setPrintRequestUrlOnFailure(enabled);
}
/**
* Set the OkHttpClient used for requesting map resources.
*
* @param client the OkHttpClient
+ * @deprecated use {@link com.mapbox.mapboxsdk.module.http.HttpRequestUtil#setOkHttpClient(OkHttpClient)} instead.
*/
+ @Deprecated
public static void setOkHttpClient(OkHttpClient client) {
- HTTPRequest.setOKHttpClient(client);
+ com.mapbox.mapboxsdk.module.http.HttpRequestUtil.setOkHttpClient(client);
}
-
} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpResponder.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpResponder.java
new file mode 100644
index 0000000000..a050e07c52
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpResponder.java
@@ -0,0 +1,32 @@
+package com.mapbox.mapboxsdk.http;
+
+/**
+ * Interface definition for a callback to be invoked when either a response was returned for a requested resource or
+ * when an error occurred when requesting the resource.
+ */
+public interface HttpResponder {
+
+ /**
+ * Invoked when a resource has finished.
+ *
+ * @param responseCode http response code
+ * @param eTag http header, identifier for a specific version of a resource
+ * @param lastModified http header, used to determine if a resource hasn't been modified since
+ * @param cacheControl http header, used to determine cache strategy of a resource
+ * @param expires http header, used to determine when a resource is stale
+ * @param retryAfter http header, used to indicate when the service is expected to be unavailable to the client
+ * @param xRateLimitReset http header, used to determine the remaining window before the rate limit resets
+ * @param body http response body, in an array of bytes representation
+ */
+ void onResponse(int responseCode, String eTag, String lastModified, String cacheControl, String expires,
+ String retryAfter, String xRateLimitReset, byte[] body);
+
+ /**
+ * Invoked when a resource failed to be retrieved.
+ *
+ * @param type the error type, either one of {@link HttpRequest#CONNECTION_ERROR},
+ * {@link HttpRequest#TEMPORARY_ERROR} or {@link HttpRequest#PERMANENT_ERROR}
+ * @param errorMessage the error message associated with the failure
+ */
+ void handleFailure(int type, String errorMessage);
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/LocalRequestTask.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/LocalRequestTask.java
index 8f31364c39..b8ed407417 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/LocalRequestTask.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/LocalRequestTask.java
@@ -3,13 +3,15 @@ package com.mapbox.mapboxsdk.http;
import android.content.res.AssetManager;
import android.os.AsyncTask;
import com.mapbox.mapboxsdk.Mapbox;
-import timber.log.Timber;
+import com.mapbox.mapboxsdk.log.Logger;
import java.io.IOException;
import java.io.InputStream;
class LocalRequestTask extends AsyncTask<String, Void, byte[]> {
+ private static final String TAG = "Mbgl-LocalRequestTask";
+
private OnLocalRequestResponse requestResponse;
LocalRequestTask(OnLocalRequestResponse requestResponse) {
@@ -40,7 +42,7 @@ class LocalRequestTask extends AsyncTask<String, Void, byte[]> {
buffer = new byte[size];
input.read(buffer);
} catch (IOException exception) {
- Timber.e(exception);
+ Logger.e(TAG, "Load file failed", exception);
}
return buffer;
}
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..5535e20923
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/NativeHttpRequest.java
@@ -0,0 +1,85 @@
+package com.mapbox.mapboxsdk.http;
+
+import android.support.annotation.Keep;
+import com.mapbox.mapboxsdk.Mapbox;
+
+import java.util.concurrent.locks.ReentrantLock;
+
+public class NativeHttpRequest implements HttpResponder {
+
+ private final HttpRequest httpRequest = Mapbox.getModuleProvider().createHttpRequest();
+
+ // Reentrancy is not needed, but "Lock" is an abstract class.
+ private final ReentrantLock lock = new ReentrantLock();
+
+ @Keep
+ private long nativePtr;
+
+ @Keep
+ 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.executeRequest(this, nativePtr, resourceUrl, etag, modified);
+ }
+
+ public void cancel() {
+ httpRequest.cancelRequest();
+
+ // 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();
+ }
+
+ @Keep
+ private native void nativeOnFailure(int type, String message);
+
+ @Keep
+ private native void nativeOnResponse(int code, String etag, String modified, String cacheControl, String expires,
+ String retryAfter, String xRateLimitReset, byte[] body);
+}