diff --git a/platform/android/MapboxGLAndroidModuleBase/.gitignore b/platform/android/MapboxGLAndroidModuleBase/.gitignore new file mode 100644 index 00000000000..796b96d1c40 --- /dev/null +++ b/platform/android/MapboxGLAndroidModuleBase/.gitignore @@ -0,0 +1 @@ +/build diff --git a/platform/android/MapboxGLAndroidModuleBase/build.gradle b/platform/android/MapboxGLAndroidModuleBase/build.gradle new file mode 100644 index 00000000000..aedbb26a8ae --- /dev/null +++ b/platform/android/MapboxGLAndroidModuleBase/build.gradle @@ -0,0 +1,25 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion androidVersions.compileSdkVersion + + defaultConfig { + minSdkVersion androidVersions.minSdkVersion + targetSdkVersion androidVersions.targetSdkVersion + buildConfigField "String", "MAPBOX_VERSION_STRING", String.format("\"Mapbox/%s\"", project.VERSION_NAME) + buildConfigField "String", "MAPBOX_SDK_IDENTIFIER", String.format("\"%s\"", "mapbox-maps-android") + buildConfigField "String", "MAPBOX_SDK_VERSION", String.format("\"%s\"", project.VERSION_NAME) + versionCode 1 + versionName "1.0" + buildConfigField "String", "MAPBOX_EVENTS_USER_AGENT", String.format("\"MapboxEventsAndroid/%s\"", project.VERSION_NAME) + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + dependencies { + implementation dependenciesList.supportAnnotations + } +} \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidModuleBase/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidModuleBase/src/main/AndroidManifest.xml new file mode 100644 index 00000000000..1ac48e6903b --- /dev/null +++ b/platform/android/MapboxGLAndroidModuleBase/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java b/platform/android/MapboxGLAndroidModuleBase/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java similarity index 100% rename from platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java rename to platform/android/MapboxGLAndroidModuleBase/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java diff --git a/platform/android/MapboxGLAndroidModuleBase/src/main/java/com/mapbox/mapboxsdk/constants/TelemetryConstants.java b/platform/android/MapboxGLAndroidModuleBase/src/main/java/com/mapbox/mapboxsdk/constants/TelemetryConstants.java new file mode 100644 index 00000000000..31a1baea4ab --- /dev/null +++ b/platform/android/MapboxGLAndroidModuleBase/src/main/java/com/mapbox/mapboxsdk/constants/TelemetryConstants.java @@ -0,0 +1,13 @@ +package com.mapbox.mapboxsdk.constants; + +public class TelemetryConstants { + + public static final String TWO_FINGER_TAP = "TwoFingerTap"; + public static final String DOUBLE_TAP = "DoubleTap"; + public static final String SINGLE_TAP = "SingleTap"; + public static final String PAN = "Pan"; + public static final String PINCH = "Pinch"; + public static final String ROTATION = "Rotation"; + public static final String PITCH = "Pitch"; + +} diff --git a/platform/android/MapboxGLAndroidModuleBase/src/main/java/com/mapbox/mapboxsdk/http/HttpRequest.java b/platform/android/MapboxGLAndroidModuleBase/src/main/java/com/mapbox/mapboxsdk/http/HttpRequest.java new file mode 100644 index 00000000000..786aa1143bd --- /dev/null +++ b/platform/android/MapboxGLAndroidModuleBase/src/main/java/com/mapbox/mapboxsdk/http/HttpRequest.java @@ -0,0 +1,95 @@ +package com.mapbox.mapboxsdk.http; + +import android.content.Context; +import android.content.pm.PackageInfo; +import android.support.annotation.NonNull; +import com.mapbox.mapboxsdk.utils.MapboxConfigurationWrapper; + +/** + * Base class for performing core http requests. + *

+ * This abstraction allows to provide alternative implementations for the http interaction of this library. + *

+ */ +public abstract class HttpRequest { + + static final int CONNECTION_ERROR = 0; + static final int TEMPORARY_ERROR = 1; + static final 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 + */ + public abstract void executeRequest(HttpRequestResponder httpRequest, long nativePtr, String resourceUrl, + String etag, String modified); + + /** + * Cancels the request. + */ + public abstract void cancelRequest(); + + // + // Utility methods + // + + /** + * Returns the application identifier, consisting out the package name, version name and version code. + * + * @return the appliciation identifier + */ + static String getApplicationIdentifier() { + return getApplicationIdentifier(MapboxConfigurationWrapper.getContext()); + } + + /** + * 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 appliciation identifier + */ + private static String getApplicationIdentifier(@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 ""; + } + } + + /** + * 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 + */ + 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 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/MapboxGLAndroidModuleBase/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestResponder.java b/platform/android/MapboxGLAndroidModuleBase/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestResponder.java new file mode 100644 index 00000000000..9d67e3c2810 --- /dev/null +++ b/platform/android/MapboxGLAndroidModuleBase/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestResponder.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 HttpRequestResponder { + + /** + * 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/MapboxGLAndroidModuleBase/src/main/java/com/mapbox/mapboxsdk/log/Logger.java b/platform/android/MapboxGLAndroidModuleBase/src/main/java/com/mapbox/mapboxsdk/log/Logger.java new file mode 100644 index 00000000000..955df1ad5cb --- /dev/null +++ b/platform/android/MapboxGLAndroidModuleBase/src/main/java/com/mapbox/mapboxsdk/log/Logger.java @@ -0,0 +1,118 @@ +package com.mapbox.mapboxsdk.log; + +import android.util.Log; + +public final class Logger { + + private static final LoggerDefinition DEFAULT = new LoggerDefinition() { + + @Override + public void v(String tag, String msg) { + Log.v(tag, msg); + } + + @Override + public void v(String tag, String msg, Throwable tr) { + Log.v(tag, msg, tr); + } + + @Override + public void d(String tag, String msg) { + Log.d(tag, msg); + } + + @Override + public void d(String tag, String msg, Throwable tr) { + Log.d(tag, msg, tr); + } + + @Override + public void i(String tag, String msg) { + Log.i(tag, msg); + } + + @Override + public void i(String tag, String msg, Throwable tr) { + Log.i(tag, msg, tr); + } + + @Override + public void w(String tag, String msg) { + Log.w(tag, msg); + } + + @Override + public void w(String tag, String msg, Throwable tr) { + Log.w(tag, msg, tr); + } + + @Override + public void w(String tag, Throwable tr) { + Log.w(tag, tr); + } + + @Override + public void e(String tag, String msg) { + Log.e(tag, msg); + } + + @Override + public void e(String tag, String msg, Throwable tr) { + Log.e(tag, msg, tr); + } + }; + + private static volatile LoggerDefinition logger = DEFAULT; + + public static void setLoggerDefinition(LoggerDefinition loggerDefinition) { + logger = loggerDefinition; + } + + public static void v(String tag, String msg) { + logger.v(tag, msg); + } + + public static void v(String tag, String msg, Throwable tr) { + logger.v(tag, msg, tr); + } + + public static void d(String tag, String msg) { + logger.d(tag, msg); + } + + public static void d(String tag, String msg, Throwable tr) { + logger.d(tag, msg, tr); + } + + public static void i(String tag, String msg) { + logger.i(tag, msg); + } + + public static void i(String tag, String msg, Throwable tr) { + logger.i(tag, msg, tr); + } + + public static void w(String tag, String msg) { + logger.w(tag, msg); + } + + public static void w(String tag, String msg, Throwable tr) { + logger.w(tag, msg, tr); + } + + public static void w(String tag, Throwable tr) { + logger.w(tag, tr); + } + + public static void e(String tag, String msg) { + logger.e(tag, msg); + } + + public static void e(String tag, String msg, Throwable tr) { + logger.e(tag, msg, tr); + } + + public static void log(int severity, String tag, String message) { + LoggerDefinition.log(severity, tag, message); + } +} \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidModuleBase/src/main/java/com/mapbox/mapboxsdk/log/LoggerDefinition.java b/platform/android/MapboxGLAndroidModuleBase/src/main/java/com/mapbox/mapboxsdk/log/LoggerDefinition.java new file mode 100644 index 00000000000..fcb2a7faa79 --- /dev/null +++ b/platform/android/MapboxGLAndroidModuleBase/src/main/java/com/mapbox/mapboxsdk/log/LoggerDefinition.java @@ -0,0 +1,50 @@ +package com.mapbox.mapboxsdk.log; + +import android.util.Log; + +public interface LoggerDefinition { + + void v(String tag, String msg); + + void v(String tag, String msg, Throwable tr); + + void d(String tag, String msg); + + void d(String tag, String msg, Throwable tr); + + void i(String tag, String msg); + + void i(String tag, String msg, Throwable tr); + + void w(String tag, String msg); + + void w(String tag, String msg, Throwable tr); + + void w(String tag, Throwable tr); + + void e(String tag, String msg); + + void e(String tag, String msg, Throwable tr); + + static void log(int severity, String tag, String message) { + switch (severity) { + case Log.VERBOSE: + Logger.v(tag, message); + break; + case Log.DEBUG: + Logger.d(tag, message); + break; + case Log.INFO: + Logger.i(tag, message); + break; + case Log.WARN: + Logger.w(tag, message); + break; + case Log.ERROR: + Logger.e(tag, message); + break; + default: + throw new UnsupportedOperationException(); + } + } +} \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidModuleBase/src/main/java/com/mapbox/mapboxsdk/telemetry/TelemetryBase.java b/platform/android/MapboxGLAndroidModuleBase/src/main/java/com/mapbox/mapboxsdk/telemetry/TelemetryBase.java new file mode 100644 index 00000000000..8e429e4f234 --- /dev/null +++ b/platform/android/MapboxGLAndroidModuleBase/src/main/java/com/mapbox/mapboxsdk/telemetry/TelemetryBase.java @@ -0,0 +1,13 @@ +package com.mapbox.mapboxsdk.telemetry; + +public interface TelemetryBase { + + void onAppUserTurnstileEvent(); + void onGestureInteraction(String eventType, double latitude, double longitude, double zoom); + + void enableOnUserRequest(); + void disableOnUserRequest(); + void setDebugLoggingEnabled(boolean debugLoggingEnabled); + void setSessionIdRotationInterval(int interval); + +} diff --git a/platform/android/MapboxGLAndroidModuleBase/src/main/java/com/mapbox/mapboxsdk/utils/MapboxConfigurationWrapper.java b/platform/android/MapboxGLAndroidModuleBase/src/main/java/com/mapbox/mapboxsdk/utils/MapboxConfigurationWrapper.java new file mode 100644 index 00000000000..8690cb7efb0 --- /dev/null +++ b/platform/android/MapboxGLAndroidModuleBase/src/main/java/com/mapbox/mapboxsdk/utils/MapboxConfigurationWrapper.java @@ -0,0 +1,43 @@ +package com.mapbox.mapboxsdk.utils; + +import android.content.Context; +import android.content.ContextWrapper; + +/** + * Application context wrapper, provides context to modular components. + *

+ * Initialised as part of Mapbox.java. + *

+ */ +public class MapboxConfigurationWrapper extends ContextWrapper { + + private static MapboxConfigurationWrapper instance; + private static String accessToken; + + public static synchronized MapboxConfigurationWrapper initialize(Context context, String accessToken) { + if (instance == null) { + instance = new MapboxConfigurationWrapper(context.getApplicationContext(), accessToken); + } + return instance; + } + + private MapboxConfigurationWrapper(Context base, String token) { + super(base.getApplicationContext()); + accessToken = token; + } + + public static Context getContext() { + Context context = instance.getBaseContext(); + if (context == null) { + throw new IllegalStateException("MapboxConfigurationWrapper isn't initialised correctly."); + } + return instance.getBaseContext(); + } + + public static String getAccessToken() { + if (accessToken == null) { + throw new IllegalStateException("MapboxConfigurationWrapper isn't initialised correctly."); + } + return accessToken; + } +} diff --git a/platform/android/MapboxGLAndroidModuleHttp/.gitignore b/platform/android/MapboxGLAndroidModuleHttp/.gitignore new file mode 100644 index 00000000000..796b96d1c40 --- /dev/null +++ b/platform/android/MapboxGLAndroidModuleHttp/.gitignore @@ -0,0 +1 @@ +/build diff --git a/platform/android/MapboxGLAndroidModuleHttp/build.gradle b/platform/android/MapboxGLAndroidModuleHttp/build.gradle new file mode 100644 index 00000000000..c31f28b1e1f --- /dev/null +++ b/platform/android/MapboxGLAndroidModuleHttp/build.gradle @@ -0,0 +1,29 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion androidVersions.compileSdkVersion + + defaultConfig { + minSdkVersion androidVersions.minSdkVersion + targetSdkVersion androidVersions.targetSdkVersion + versionCode 1 + versionName "1.0" + buildConfigField "String", "GIT_REVISION_SHORT", String.format("\"%s\"", getGitRevision()) + buildConfigField "String", "MAPBOX_VERSION_STRING", String.format("\"Mapbox/%s\"", project.VERSION_NAME) + } +} + +dependencies { + api(project(':MapboxGLAndroidModuleBase')) + implementation dependenciesList.okhttp3 + implementation dependenciesList.supportAnnotations + implementation dependenciesList.timber +} + +def static getGitRevision() { + def cmd = "git rev-parse --short HEAD" + def proc = cmd.execute() + def ref = proc.text.trim() + return ref +} + diff --git a/platform/android/MapboxGLAndroidModuleHttp/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidModuleHttp/src/main/AndroidManifest.xml new file mode 100644 index 00000000000..bb661323470 --- /dev/null +++ b/platform/android/MapboxGLAndroidModuleHttp/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/platform/android/MapboxGLAndroidModuleHttp/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestImpl.java b/platform/android/MapboxGLAndroidModuleHttp/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestImpl.java new file mode 100644 index 00000000000..c562f1b1478 --- /dev/null +++ b/platform/android/MapboxGLAndroidModuleHttp/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestImpl.java @@ -0,0 +1,186 @@ +package com.mapbox.mapboxsdk.http; + +import android.os.Build; +import android.support.annotation.NonNull; +import android.text.TextUtils; +import android.util.Log; +import com.mapbox.mapboxsdk.constants.MapboxConstants; +import okhttp3.*; +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 static com.mapbox.mapboxsdk.http.HttpRequestUtil.toHumanReadableAscii; + +public class HttpRequestImpl extends HttpRequest { + + private static final String userAgentString = 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; + + private Call call; + + @Override + public void executeRequest(HttpRequestResponder httpRequest, long nativePtr, String resourceUrl, + String etag, String modified) { + 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)); + return; + } + + final String host = httpUrl.host().toLowerCase(MapboxConstants.MAPBOX_LOCALE); + resourceUrl = buildResourceUrl(host, resourceUrl, httpUrl.querySize()); + + final Request.Builder builder = new Request.Builder() + .url(resourceUrl) + .tag(resourceUrl.toLowerCase(MapboxConstants.MAPBOX_LOCALE)) + .addHeader("User-Agent", userAgentString); + if (etag.length() > 0) { + builder.addHeader("If-None-Match", etag); + } else if (modified.length() > 0) { + builder.addHeader("If-Modified-Since", modified); + } + + final Request request = builder.build(); + call = client.newCall(request); + call.enqueue(callback); + } catch (Exception exception) { + callback.handleFailure(call, exception); + } + } + + @Override + public void cancelRequest() { + // call can be null if the constructor gets aborted (e.g, under a NoRouteToHostException). + if (call != null) { + call.cancel(); + } + } + + public static void enablePrintRequestUrlOnFailure(boolean enabled) { + logRequestUrl = enabled; + } + + public static void enableLog(boolean enabled) { + logEnabled = enabled; + } + + public static void setOkHttpClient(OkHttpClient okHttpClient) { + HttpRequestImpl.client = okHttpClient; + } + + private static class OkHttpCallback implements Callback { + + private HttpRequestResponder httpRequest; + + OkHttpCallback(HttpRequestResponder 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)); + } + + 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); + } + 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 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); + } + } +} \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUtil.java b/platform/android/MapboxGLAndroidModuleHttp/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUtil.java similarity index 52% rename from platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUtil.java rename to platform/android/MapboxGLAndroidModuleHttp/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUtil.java index 872032867ae..d8b9591a634 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUtil.java +++ b/platform/android/MapboxGLAndroidModuleHttp/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUtil.java @@ -1,14 +1,15 @@ package com.mapbox.mapboxsdk.http; import okhttp3.OkHttpClient; +import okio.Buffer; /** - * 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. *

* This configuration will outlast the lifecycle of the Map. *

@@ -16,7 +17,7 @@ public class HttpRequestUtil { * @param enabled True will enable logging, false will disable */ public static void setLogEnabled(boolean enabled) { - HTTPRequest.enableLog(enabled); + HttpRequestImpl.enableLog(enabled); } /** @@ -31,7 +32,7 @@ public static void setLogEnabled(boolean enabled) { * @param enabled True will print urls, false will disable */ public static void setPrintRequestUrlOnFailure(boolean enabled) { - HTTPRequest.enablePrintRequestUrlOnFailure(enabled); + HttpRequestImpl.enablePrintRequestUrlOnFailure(enabled); } /** @@ -40,7 +41,24 @@ public static void setPrintRequestUrlOnFailure(boolean enabled) { * @param client the OkHttpClient */ public static void setOkHttpClient(OkHttpClient client) { - HTTPRequest.setOKHttpClient(client); + HttpRequestImpl.setOkHttpClient(client); } + static String toHumanReadableAscii(String s) { + for (int i = 0, length = s.length(), c; i < length; i += Character.charCount(c)) { + c = s.codePointAt(i); + if (c > '\u001f' && c < '\u007f') { + continue; + } + + Buffer buffer = new Buffer(); + buffer.writeUtf8(s, 0, i); + for (int j = i; j < length; j += Character.charCount(c)) { + c = s.codePointAt(j); + buffer.writeUtf8CodePoint(c > '\u001f' && c < '\u007f' ? c : '?'); + } + return buffer.readUtf8(); + } + return s; + } } \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidModuleTelemetry/.gitignore b/platform/android/MapboxGLAndroidModuleTelemetry/.gitignore new file mode 100644 index 00000000000..796b96d1c40 --- /dev/null +++ b/platform/android/MapboxGLAndroidModuleTelemetry/.gitignore @@ -0,0 +1 @@ +/build diff --git a/platform/android/MapboxGLAndroidModuleTelemetry/build.gradle b/platform/android/MapboxGLAndroidModuleTelemetry/build.gradle new file mode 100644 index 00000000000..41c3c6f6ddb --- /dev/null +++ b/platform/android/MapboxGLAndroidModuleTelemetry/build.gradle @@ -0,0 +1,19 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 28 + + defaultConfig { + minSdkVersion 14 + targetSdkVersion 28 + versionCode 1 + versionName "1.0" + } +} + +dependencies { + api(project(':MapboxGLAndroidModuleBase')) + api (dependenciesList.mapboxAndroidTelemetry) { + exclude group: 'com.android.support', module: 'appcompat-v7' + } +} diff --git a/platform/android/MapboxGLAndroidModuleTelemetry/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidModuleTelemetry/src/main/AndroidManifest.xml new file mode 100644 index 00000000000..9ae6d017cfc --- /dev/null +++ b/platform/android/MapboxGLAndroidModuleTelemetry/src/main/AndroidManifest.xml @@ -0,0 +1 @@ + diff --git a/platform/android/MapboxGLAndroidModuleTelemetry/src/main/java/com/mapbox/mapboxsdk/telemetry/Telemetry.java b/platform/android/MapboxGLAndroidModuleTelemetry/src/main/java/com/mapbox/mapboxsdk/telemetry/Telemetry.java new file mode 100644 index 00000000000..5bb3c38dac7 --- /dev/null +++ b/platform/android/MapboxGLAndroidModuleTelemetry/src/main/java/com/mapbox/mapboxsdk/telemetry/Telemetry.java @@ -0,0 +1,66 @@ +package com.mapbox.mapboxsdk.telemetry; + +import android.content.Context; +import com.mapbox.android.telemetry.AppUserTurnstile; +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.android.telemetry.SessionInterval; +import com.mapbox.android.telemetry.TelemetryEnabler; +import com.mapbox.mapboxsdk.module.BuildConfig; +import com.mapbox.mapboxsdk.utils.MapboxConfigurationWrapper; + +public class Telemetry implements TelemetryBase { + + private MapboxTelemetry telemetry; + + public Telemetry() { + Context appContext = MapboxConfigurationWrapper.getContext(); + String accessToken = MapboxConfigurationWrapper.getAccessToken(); + telemetry = new MapboxTelemetry(appContext, accessToken, BuildConfig.MAPBOX_EVENTS_USER_AGENT); + TelemetryEnabler.State telemetryState = TelemetryEnabler.retrieveTelemetryStateFromPreferences(); + if (TelemetryEnabler.State.ENABLED.equals(telemetryState)) { + telemetry.enable(); + } + } + + @Override + public void onAppUserTurnstileEvent() { + 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)); + } + + @Override + public void onGestureInteraction(String eventType, double latitude, double longitude, double zoom) { + MapEventFactory mapEventFactory = new MapEventFactory(); + MapState state = new MapState(latitude, longitude, zoom); + state.setGesture(eventType); + telemetry.push(mapEventFactory.createMapGestureEvent(Event.Type.MAP_CLICK, state)); + } + + @Override + public void enableOnUserRequest() { + TelemetryEnabler.updateTelemetryState(TelemetryEnabler.State.ENABLED); + telemetry.enable(); + } + + @Override + public void disableOnUserRequest() { + telemetry.disable(); + TelemetryEnabler.updateTelemetryState(TelemetryEnabler.State.DISABLED); + } + + @Override + public void setDebugLoggingEnabled(boolean debugLoggingEnabled) { + telemetry.updateDebugLoggingEnabled(debugLoggingEnabled); + } + + @Override + public void setSessionIdRotationInterval(int interval) { + telemetry.updateSessionIdRotationInterval(new SessionInterval(interval)); + } +} diff --git a/platform/android/MapboxGLAndroidSDK/build.gradle b/platform/android/MapboxGLAndroidSDK/build.gradle index 35b4de003be..b14477d4811 100644 --- a/platform/android/MapboxGLAndroidSDK/build.gradle +++ b/platform/android/MapboxGLAndroidSDK/build.gradle @@ -2,17 +2,17 @@ apply plugin: 'com.android.library' apply plugin: "com.jaredsburrows.license" dependencies { - api (dependenciesList.mapboxAndroidTelemetry) { - exclude group: 'com.android.support', module: 'appcompat-v7' - } + api(project(':MapboxGLAndroidModuleBase')) + api(project(':MapboxGLAndroidModuleHttp')) + api(project(':MapboxGLAndroidModuleTelemetry')) + api dependenciesList.mapboxJavaGeoJSON api (dependenciesList.mapboxAndroidGestures) { exclude group: 'com.android.support', module: 'appcompat-v7' } implementation dependenciesList.supportAnnotations implementation dependenciesList.supportFragmentV4 - implementation dependenciesList.timber - implementation dependenciesList.okhttp3 + implementation dependenciesList.supportUtilV4 testImplementation dependenciesList.junit testImplementation dependenciesList.mockito testImplementation dependenciesList.robolectric @@ -25,15 +25,11 @@ android { defaultConfig { minSdkVersion androidVersions.minSdkVersion targetSdkVersion androidVersions.targetSdkVersion - buildConfigField "String", "GIT_REVISION_SHORT", String.format("\"%s\"", getGitRevision()) - buildConfigField "String", "MAPBOX_SDK_IDENTIFIER", String.format("\"%s\"", "mapbox-maps-android") - buildConfigField "String", "MAPBOX_SDK_VERSION", String.format("\"%s\"", project.VERSION_NAME) - buildConfigField "String", "MAPBOX_VERSION_STRING", String.format("\"Mapbox/%s\"", project.VERSION_NAME) - buildConfigField "String", "MAPBOX_EVENTS_USER_AGENT", String.format("\"MapboxEventsAndroid/%s\"", project.VERSION_NAME) } defaultPublishConfig project.hasProperty("mapbox.buildtype") ? project.getProperty("mapbox.buildtype") : "debug" + // We sometimes want to invoke Gradle without building a native dependency, e.g. when we just want // to invoke the Java tests. When we explicitly specify an ABI of 'none', no native dependencies are // added. When another ABI is specified explicitly, we're just going to build that ABI. In all other @@ -142,13 +138,6 @@ licenseReport { copyJsonReportToAssets = false } -def static getGitRevision() { - def cmd = "git rev-parse --short HEAD" - def proc = cmd.execute() - def ref = proc.text.trim() - return ref -} - configurations { all*.exclude group: 'commons-logging', module: 'commons-logging' all*.exclude group: 'commons-collections', module: 'commons-collections' diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/LibraryLoader.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/LibraryLoader.java index 6633d5d9525..a91e4bdf140 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/LibraryLoader.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/LibraryLoader.java @@ -1,6 +1,6 @@ package com.mapbox.mapboxsdk; -import timber.log.Timber; +import com.mapbox.mapboxsdk.log.Logger; /** * Loads the mapbox-gl shared library @@ -11,6 +11,8 @@ */ public abstract class LibraryLoader { + private static final String TAG = "LibraryLoader"; + private static final LibraryLoader DEFAULT = new LibraryLoader() { @Override public void load(String name) { @@ -39,7 +41,7 @@ public static void load() { try { loader.load("mapbox-gl"); } catch (UnsatisfiedLinkError error) { - Timber.e(error, "Failed to load native shared library."); + Logger.e(TAG, "Failed to load native shared library.", error); } } 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 a8094603755..5db824967d0 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 @@ -1,6 +1,5 @@ package com.mapbox.mapboxsdk; -import android.annotation.SuppressLint; import android.content.Context; import android.net.ConnectivityManager; import android.net.NetworkInfo; @@ -10,9 +9,10 @@ import android.text.TextUtils; import com.mapbox.mapboxsdk.constants.MapboxConstants; import com.mapbox.mapboxsdk.exceptions.MapboxConfigurationException; -import com.mapbox.mapboxsdk.maps.Telemetry; +import com.mapbox.mapboxsdk.log.Logger; import com.mapbox.mapboxsdk.net.ConnectivityReceiver; -import timber.log.Timber; +import com.mapbox.mapboxsdk.telemetry.Telemetry; +import com.mapbox.mapboxsdk.utils.MapboxConfigurationWrapper; /** * The entry point to initialize the Mapbox Android SDK. @@ -25,10 +25,10 @@ @UiThread public final class Mapbox { - @SuppressLint("StaticFieldLeak") + private static final String TAG = "Mapbox"; + private static Mapbox INSTANCE; - private Context context; - private String accessToken; + private Telemetry telemetry; private Boolean connected; /** @@ -41,22 +41,20 @@ public final class Mapbox { * @param accessToken Mapbox access token * @return the single instance of Mapbox */ - @UiThread public static synchronized Mapbox getInstance(@NonNull Context context, @Nullable String accessToken) { if (INSTANCE == null) { - Context appContext = context.getApplicationContext(); - INSTANCE = new Mapbox(appContext, accessToken); - if (isAccessTokenValid(accessToken)) { - initializeTelemetry(); - } - ConnectivityReceiver.instance(appContext); + INSTANCE = new Mapbox(context, accessToken); } return INSTANCE; } Mapbox(@NonNull Context context, @Nullable String accessToken) { - this.context = context; - this.accessToken = accessToken; + Context appContext = context.getApplicationContext(); + MapboxConfigurationWrapper.initialize(appContext, accessToken); + if (isAccessTokenValid(accessToken)) { + initializeTelemetry(); + } + ConnectivityReceiver.instance(appContext); } /** @@ -67,7 +65,7 @@ public static synchronized Mapbox getInstance(@NonNull Context context, @Nullabl @Nullable public static String getAccessToken() { validateMapbox(); - return INSTANCE.accessToken; + return MapboxConfigurationWrapper.getAccessToken(); } /** @@ -78,7 +76,21 @@ public static String getAccessToken() { @NonNull public static Context getApplicationContext() { validateMapbox(); - return INSTANCE.context; + return MapboxConfigurationWrapper.getContext(); + } + + /** + * Telemetry instance + *

+ * If no valid mapbox accesstoken was provided, this method returns null. + *

+ * + * @return the telemetry instance; + */ + @Nullable + public static Telemetry getTelemetry() { + validateMapbox(); + return INSTANCE.telemetry; } /** @@ -107,7 +119,8 @@ public static synchronized Boolean isConnected() { return INSTANCE.connected; } - ConnectivityManager cm = (ConnectivityManager) INSTANCE.context.getSystemService(Context.CONNECTIVITY_SERVICE); + Context context = MapboxConfigurationWrapper.getContext(); + ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); return (activeNetwork != null && activeNetwork.isConnected()); } @@ -117,9 +130,9 @@ public static synchronized Boolean isConnected() { */ private static void initializeTelemetry() { try { - Telemetry.initialize(); + INSTANCE.telemetry = new Telemetry(); } catch (Exception exception) { - Timber.e(exception); + Logger.e(TAG, "Error occured while initializing telemetry", exception); } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/Attribution.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/Attribution.java index 0877b3ab978..b5030c8677e 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/Attribution.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/Attribution.java @@ -4,7 +4,7 @@ public class Attribution { private static final String OPENSTREETMAP = "OpenStreetMap"; private static final String OPENSTREETMAP_ABBR = "OSM"; - static final String TELEMETRY = "Telemetry Settings"; + static final String TELEMETRY = "TelemetryBase Settings"; static final String IMPROVE_MAP_URL = "https://www.mapbox.com/map-feedback/"; static final String MAPBOX_URL = "https://www.mapbox.com/about/maps/"; diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxConfigurationException.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxConfigurationException.java index 86032aa2b5b..1add1bf0a93 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxConfigurationException.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxConfigurationException.java @@ -17,7 +17,7 @@ public class MapboxConfigurationException extends RuntimeException { * Creates a Mapbox configuration exception thrown by MapboxMap when the SDK hasn't been properly initialised. */ public MapboxConfigurationException() { - super("\nUsing MapView requires calling Mapbox.getInstance(Context context, String accessToken) before " + super("\nUsing MapView requires calling Mapbox.initialize(Context context, String accessToken) before " + "inflating or creating the view. The access token parameter is required when using a Mapbox service." + "\nPlease see https://www.mapbox.com/help/create-api-access-token/ to learn how to create one." + "\nMore information in this guide https://www.mapbox.com/help/first-steps-android-sdk/#access-tokens."); 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 e0c63944b90..00000000000 --- 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/LocalRequestTask.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/LocalRequestTask.java index 8f31364c391..61dc367ab77 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 @@ 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 { + private static final String TAG = "LocalRequestTask"; + private OnLocalRequestResponse requestResponse; LocalRequestTask(OnLocalRequestResponse requestResponse) { @@ -40,7 +42,7 @@ private static byte[] loadFile(AssetManager assets, String path) { 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 00000000000..eb4a7261630 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/NativeHttpRequest.java @@ -0,0 +1,77 @@ +package com.mapbox.mapboxsdk.http; + +import java.util.concurrent.locks.ReentrantLock; + +public class NativeHttpRequest implements HttpRequestResponder { + + private final HttpRequestImpl httpRequestImpl = new HttpRequestImpl(); + + // 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; + } + httpRequestImpl.executeRequest(this, nativePtr, resourceUrl, etag, modified); + } + + public void cancel() { + httpRequestImpl.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(); + } + + 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/maps/AnnotationManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java index 64b33ad5986..b80af49e7be 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java @@ -8,7 +8,6 @@ import android.support.annotation.Nullable; import android.support.v4.util.LongSparseArray; import android.view.View; - import com.mapbox.mapboxsdk.Mapbox; import com.mapbox.mapboxsdk.R; import com.mapbox.mapboxsdk.annotations.Annotation; @@ -21,12 +20,11 @@ import com.mapbox.mapboxsdk.annotations.PolygonOptions; import com.mapbox.mapboxsdk.annotations.Polyline; import com.mapbox.mapboxsdk.annotations.PolylineOptions; +import com.mapbox.mapboxsdk.log.Logger; import java.util.ArrayList; import java.util.List; -import timber.log.Timber; - /** * Responsible for managing and tracking state of Annotations linked to Map. All events related to * annotations that occur on {@link MapboxMap} are forwarded to this class. @@ -40,6 +38,8 @@ */ class AnnotationManager { + private final static String TAG = "AnnotationManager"; + private static final long NO_ANNOTATION_ID = -1; private final MapView mapView; @@ -369,7 +369,9 @@ private boolean isAddedToMap(Annotation annotation) { } private void logNonAdded(Annotation annotation) { - Timber.w("Attempting to update non-added %s with value %s", annotation.getClass().getCanonicalName(), annotation); + Logger.w(TAG, String.format( + "Attempting to update non-added %s with value %s", annotation.getClass().getCanonicalName(), annotation) + ); } // diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java index 546ee628048..7cddaaa9525 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java @@ -11,6 +11,7 @@ import android.view.View; import android.widget.ArrayAdapter; import android.widget.Toast; +import com.mapbox.mapboxsdk.Mapbox; import com.mapbox.mapboxsdk.R; import com.mapbox.mapboxsdk.attribution.Attribution; import com.mapbox.mapboxsdk.attribution.AttributionParser; @@ -97,7 +98,7 @@ private void showTelemetryDialog() { builder.setPositiveButton(R.string.mapbox_attributionTelemetryPositive, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - Telemetry.enableOnUserRequest(); + Mapbox.getTelemetry().enableOnUserRequest(); dialog.cancel(); } }); @@ -111,7 +112,7 @@ public void onClick(DialogInterface dialog, int which) { builder.setNegativeButton(R.string.mapbox_attributionTelemetryNegative, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - Telemetry.disableOnUserRequest(); + Mapbox.getTelemetry().disableOnUserRequest(); dialog.cancel(); } }); 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 fc4b13a293c..1f10e023a44 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 @@ -10,7 +10,6 @@ import android.view.InputDevice; import android.view.MotionEvent; import android.view.animation.DecelerateInterpolator; - import com.mapbox.android.gestures.AndroidGesturesManager; import com.mapbox.android.gestures.Constants; import com.mapbox.android.gestures.MoveGestureDetector; @@ -19,14 +18,13 @@ 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.Mapbox; import com.mapbox.mapboxsdk.R; import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.constants.MapboxConstants; +import com.mapbox.mapboxsdk.constants.TelemetryConstants; import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.telemetry.Telemetry; import com.mapbox.mapboxsdk.utils.MathUtils; import java.util.ArrayList; @@ -346,7 +344,7 @@ public boolean onSingleTapConfirmed(MotionEvent motionEvent) { notifyOnMapClickListeners(tapPoint); } - sendTelemetryEvent(Telemetry.SINGLE_TAP, new PointF(motionEvent.getX(), motionEvent.getY())); + sendTelemetryEvent(TelemetryConstants.SINGLE_TAP, new PointF(motionEvent.getX(), motionEvent.getY())); return true; } @@ -377,7 +375,7 @@ public boolean onDoubleTapEvent(MotionEvent motionEvent) { zoomInAnimated(zoomFocalPoint, false); - sendTelemetryEvent(Telemetry.DOUBLE_TAP, new PointF(motionEvent.getX(), motionEvent.getY())); + sendTelemetryEvent(TelemetryConstants.DOUBLE_TAP, new PointF(motionEvent.getX(), motionEvent.getY())); return true; } @@ -439,7 +437,7 @@ public boolean onMoveBegin(MoveGestureDetector detector) { } transform.cancelTransitions(); - sendTelemetryEvent(Telemetry.PAN, detector.getFocalPoint()); + sendTelemetryEvent(TelemetryConstants.PAN, detector.getFocalPoint()); notifyOnMoveBeginListeners(detector); return true; } @@ -504,7 +502,7 @@ public boolean onScaleBegin(StandardScaleGestureDetector detector) { // setting focalPoint in #onScaleBegin() as well, because #onScale() might not get called before #onScaleEnd() setScaleFocalPoint(detector); - sendTelemetryEvent(Telemetry.PINCH, scaleFocalPoint); + sendTelemetryEvent(TelemetryConstants.PINCH, scaleFocalPoint); notifyOnScaleBeginListeners(detector); @@ -625,7 +623,7 @@ public boolean onRotateBegin(RotateGestureDetector detector) { // setting in #onRotateBegin() as well, because #onRotate() might not get called before #onRotateEnd() setRotateFocalPoint(detector); - sendTelemetryEvent(Telemetry.ROTATION, rotateFocalPoint); + sendTelemetryEvent(TelemetryConstants.ROTATION, rotateFocalPoint); notifyOnRotateBeginListeners(detector); @@ -742,7 +740,7 @@ public boolean onShoveBegin(ShoveGestureDetector detector) { transform.cancelTransitions(); - sendTelemetryEvent(Telemetry.PITCH, detector.getFocalPoint()); + sendTelemetryEvent(TelemetryConstants.PITCH, detector.getFocalPoint()); // disabling move gesture during shove gesturesManager.getMoveGestureDetector().setEnabled(false); @@ -791,7 +789,7 @@ public boolean onMultiFingerTap(MultiFingerTapGestureDetector detector, int poin transform.cancelTransitions(); cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE); - sendTelemetryEvent(Telemetry.TWO_FINGER_TAP, detector.getFocalPoint()); + sendTelemetryEvent(TelemetryConstants.TWO_FINGER_TAP, detector.getFocalPoint()); PointF zoomFocalPoint; // Single finger double tap @@ -883,16 +881,15 @@ private void zoomAnimated(boolean zoomIn, PointF zoomFocalPoint, boolean runImme } private void sendTelemetryEvent(String eventType, PointF focalPoint) { - CameraPosition cameraPosition = transform.getCameraPosition(); - 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)); + Telemetry telemetry = Mapbox.getTelemetry(); + if (telemetry != null) { + CameraPosition cameraPosition = transform.getCameraPosition(); + if (cameraPosition != null) { + double zoom = cameraPosition.zoom; + if (isZoomValid(zoom)) { + LatLng latLng = projection.fromScreenLocation(focalPoint); + telemetry.onGestureInteraction(eventType, latLng.getLatitude(), latLng.getLongitude(), zoom); + } } } } 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 0fa1072cd2c..5fb682ef3b4 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.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.Mapbox; import com.mapbox.mapboxsdk.R; import com.mapbox.mapboxsdk.annotations.Annotation; import com.mapbox.mapboxsdk.annotations.MarkerViewManager; @@ -44,6 +40,7 @@ import com.mapbox.mapboxsdk.offline.OfflineRegionDefinition; import com.mapbox.mapboxsdk.offline.OfflineTilePyramidRegionDefinition; import com.mapbox.mapboxsdk.storage.FileSource; +import com.mapbox.mapboxsdk.telemetry.Telemetry; import com.mapbox.mapboxsdk.utils.BitmapUtils; import javax.microedition.khronos.egl.EGLConfig; @@ -271,12 +268,10 @@ public void onClick(View v) { @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)); + Telemetry telemetry = Mapbox.getTelemetry(); + if (telemetry != null) { + telemetry.onAppUserTurnstileEvent(); + } } else if (savedInstanceState.getBoolean(MapboxConstants.STATE_HAS_SAVED_STATE)) { this.savedInstanceState = savedInstanceState; } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java index 64ad0d29b35..b58ea601df6 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java @@ -40,11 +40,11 @@ import com.mapbox.mapboxsdk.constants.Style; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.geometry.LatLngBounds; +import com.mapbox.mapboxsdk.log.Logger; import com.mapbox.mapboxsdk.style.expressions.Expression; import com.mapbox.mapboxsdk.style.layers.Layer; import com.mapbox.mapboxsdk.style.light.Light; import com.mapbox.mapboxsdk.style.sources.Source; -import timber.log.Timber; import java.util.HashMap; import java.util.List; @@ -61,6 +61,8 @@ @UiThread public final class MapboxMap { + private static final String TAG = "MapboxMap"; + private final NativeMapView nativeMapView; private final UiSettings uiSettings; @@ -293,7 +295,7 @@ public T getLayerAs(@NonNull String layerId) { // noinspection unchecked return (T) nativeMapView.getLayer(layerId); } catch (ClassCastException exception) { - Timber.e(exception, "Layer: %s is a different type: ", layerId); + Logger.e(TAG, String.format("Layer: %s is a different type: ", layerId), exception); return null; } } @@ -405,7 +407,7 @@ public T getSourceAs(@NonNull String sourceId) { // noinspection unchecked return (T) nativeMapView.getSource(sourceId); } catch (ClassCastException exception) { - Timber.e(exception, "Source: %s is a different type: ", sourceId); + Logger.e(TAG, String.format("Source: %s is a different type: ", sourceId), exception); return null; } } @@ -1462,7 +1464,7 @@ public void setOnPolylineClickListener(@Nullable OnPolylineClickListener listene */ public void selectMarker(@NonNull Marker marker) { if (marker == null) { - Timber.w("marker was null, so just returning"); + Logger.w(TAG, "marker was null, so just returning"); return; } annotationManager.selectMarker(marker); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java index 31910b206e6..ce2bf82aa73 100755 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java @@ -23,6 +23,7 @@ import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.geometry.LatLngBounds; import com.mapbox.mapboxsdk.geometry.ProjectedMeters; +import com.mapbox.mapboxsdk.log.Logger; import com.mapbox.mapboxsdk.maps.renderer.MapRenderer; import com.mapbox.mapboxsdk.storage.FileSource; import com.mapbox.mapboxsdk.style.expressions.Expression; @@ -32,7 +33,6 @@ import com.mapbox.mapboxsdk.style.sources.CannotAddSourceException; import com.mapbox.mapboxsdk.style.sources.Source; import com.mapbox.mapboxsdk.utils.BitmapUtils; -import timber.log.Timber; import java.nio.ByteBuffer; import java.util.ArrayList; @@ -45,6 +45,8 @@ // Class that wraps the native methods for convenience final class NativeMapView { + private final static String TAG = "NativeMapView"; + //Hold a reference to prevent it from being GC'd as long as it's used on the native side private final FileSource fileSource; @@ -109,9 +111,9 @@ private boolean checkState(String callingMethod) { // validate if map has already been destroyed if (destroyed && !TextUtils.isEmpty(callingMethod)) { - Timber.e( + Logger.e(TAG, String.format( "You're calling `%s` after the `MapView` was destroyed, were you invoking it after `onDestroy()`?", - callingMethod + callingMethod) ); } return destroyed; @@ -149,15 +151,17 @@ public void resizeView(int width, int height) { if (width > 65535) { // we have seen edge cases where devices return incorrect values #6111 - Timber.e("Device returned an out of range width size, " - + "capping value at 65535 instead of %s", width); + Logger.e(TAG, String.format("Device returned an out of range width size, " + + "capping value at 65535 instead of %s", width) + ); width = 65535; } if (height > 65535) { // we have seen edge cases where devices return incorrect values #6111 - Timber.e("Device returned an out of range height size, " - + "capping value at 65535 instead of %s", height); + Logger.e(TAG, String.format("Device returned an out of range height size, " + + "capping value at 65535 instead of %s", height) + ); height = 65535; } @@ -899,7 +903,7 @@ protected void onMapChanged(int rawChange) { try { onMapChangedListener.onMapChanged(rawChange); } catch (RuntimeException err) { - Timber.e(err, "Exception in MapView.OnMapChangedListener"); + Logger.e(TAG, "Exception in MapView.OnMapChangedListener", err); } } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Telemetry.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Telemetry.java deleted file mode 100644 index 10c9ce9c832..00000000000 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Telemetry.java +++ /dev/null @@ -1,75 +0,0 @@ -package com.mapbox.mapboxsdk.maps; - - -import com.mapbox.android.telemetry.MapboxTelemetry; -import com.mapbox.android.telemetry.SessionInterval; -import com.mapbox.android.telemetry.TelemetryEnabler; -import com.mapbox.mapboxsdk.BuildConfig; -import com.mapbox.mapboxsdk.Mapbox; - -public class Telemetry { - static final String TWO_FINGER_TAP = "TwoFingerTap"; - static final String DOUBLE_TAP = "DoubleTap"; - static final String SINGLE_TAP = "SingleTap"; - static final String PAN = "Pan"; - static final String PINCH = "Pinch"; - static final String ROTATION = "Rotation"; - static final String PITCH = "Pitch"; - private MapboxTelemetry telemetry; - - private Telemetry() { - telemetry = new MapboxTelemetry(Mapbox.getApplicationContext(), Mapbox.getAccessToken(), - BuildConfig.MAPBOX_EVENTS_USER_AGENT); - TelemetryEnabler.State telemetryState = TelemetryEnabler.retrieveTelemetryStateFromPreferences(); - if (TelemetryEnabler.State.ENABLED.equals(telemetryState)) { - telemetry.enable(); - } - } - - public static void initialize() { - obtainTelemetry(); - } - - /** - * Set the debug logging state of telemetry. - * - * @param debugLoggingEnabled true to enable logging - */ - public static void updateDebugLoggingEnabled(boolean debugLoggingEnabled) { - TelemetryHolder.INSTANCE.telemetry.updateDebugLoggingEnabled(debugLoggingEnabled); - } - - /** - * Update the telemetry rotation session id interval - * - * @param interval the selected session interval - * @return true if rotation session id was updated - */ - public static boolean updateSessionIdRotationInterval(SessionInterval interval) { - return TelemetryHolder.INSTANCE.telemetry.updateSessionIdRotationInterval(interval); - } - - /** - * Method to be called when an end-user has selected to participate in telemetry collection. - */ - public static void enableOnUserRequest() { - TelemetryEnabler.updateTelemetryState(TelemetryEnabler.State.ENABLED); - TelemetryHolder.INSTANCE.telemetry.enable(); - } - - /** - * Method to be called when an end-user has selected to opt-out of telemetry collection. - */ - public static void disableOnUserRequest() { - Telemetry.obtainTelemetry().disable(); - TelemetryEnabler.updateTelemetryState(TelemetryEnabler.State.DISABLED); - } - - private static class TelemetryHolder { - private static final Telemetry INSTANCE = new Telemetry(); - } - - static MapboxTelemetry obtainTelemetry() { - return TelemetryHolder.INSTANCE.telemetry; - } -} diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java index c827e5e6366..15af8f3378b 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java @@ -5,15 +5,13 @@ import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.UiThread; - import com.mapbox.mapboxsdk.annotations.MarkerViewManager; import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.camera.CameraUpdate; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.constants.MapboxConstants; import com.mapbox.mapboxsdk.geometry.LatLng; - -import timber.log.Timber; +import com.mapbox.mapboxsdk.log.Logger; import static com.mapbox.mapboxsdk.maps.MapView.REGION_DID_CHANGE_ANIMATED; import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveStartedListener; @@ -27,6 +25,8 @@ */ final class Transform implements MapView.OnMapChangedListener { + private static final String TAG = "Transform"; + private final NativeMapView mapView; private final MarkerViewManager markerViewManager; private final Handler handler = new Handler(); @@ -339,7 +339,7 @@ public void onMapChanged(int change) { void setMinZoom(double minZoom) { if ((minZoom < MapboxConstants.MINIMUM_ZOOM) || (minZoom > MapboxConstants.MAXIMUM_ZOOM)) { - Timber.e("Not setting minZoomPreference, value is in unsupported range: %s", minZoom); + Logger.e(TAG, String.format("Not setting minZoomPreference, value is in unsupported range: %s", minZoom)); return; } mapView.setMinZoom(minZoom); @@ -351,7 +351,7 @@ void setMinZoom(double minZoom) { void setMaxZoom(double maxZoom) { if ((maxZoom < MapboxConstants.MINIMUM_ZOOM) || (maxZoom > MapboxConstants.MAXIMUM_ZOOM)) { - Timber.e("Not setting maxZoomPreference, value is in unsupported range: %s", maxZoom); + Logger.e(TAG, String.format("Not setting maxZoomPreference, value is in unsupported range: %s", maxZoom)); return; } mapView.setMaxZoom(maxZoom); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/egl/EGLConfigChooser.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/egl/EGLConfigChooser.java index 46238ee7890..de759952788 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/egl/EGLConfigChooser.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/egl/EGLConfigChooser.java @@ -3,16 +3,15 @@ import android.opengl.GLSurfaceView; import android.os.Build; import android.support.annotation.NonNull; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import com.mapbox.mapboxsdk.constants.MapboxConstants; +import com.mapbox.mapboxsdk.log.Logger; import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLDisplay; - -import timber.log.Timber; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import static com.mapbox.mapboxsdk.utils.Compare.compare; import static javax.microedition.khronos.egl.EGL10.EGL_ALPHA_MASK_SIZE; @@ -38,6 +37,8 @@ */ public class EGLConfigChooser implements GLSurfaceView.EGLConfigChooser { + private static final String TAG = "EGLConfigChooser"; + /** * Requires API level 17 * @@ -72,7 +73,7 @@ public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { // Determine number of possible configurations int[] numConfigs = getNumberOfConfigurations(egl, display, configAttribs); if (numConfigs[0] < 1) { - Timber.e("eglChooseConfig() returned no configs."); + Logger.e(TAG, "eglChooseConfig() returned no configs."); throw new EGLConfigException("eglChooseConfig() failed"); } @@ -82,7 +83,7 @@ public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { // Choose best match EGLConfig config = chooseBestMatchConfig(egl, display, possibleConfigurations); if (config == null) { - Timber.e("No config chosen"); + Logger.e(TAG, "No config chosen"); throw new EGLConfigException("No config chosen"); } @@ -92,7 +93,9 @@ public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) { private int[] getNumberOfConfigurations(EGL10 egl, EGLDisplay display, int[] configAttributes) { int[] numConfigs = new int[1]; if (!egl.eglChooseConfig(display, configAttributes, null, 0, numConfigs)) { - Timber.e("eglChooseConfig(NULL) returned error %d", egl.eglGetError()); + Logger.e(TAG, String.format( + MapboxConstants.MAPBOX_LOCALE, "eglChooseConfig(NULL) returned error %d", egl.eglGetError()) + ); throw new EGLConfigException("eglChooseConfig() failed"); } return numConfigs; @@ -102,7 +105,9 @@ private EGLConfig[] getPossibleConfigurations(EGL10 egl, EGLDisplay display, int[] configAttributes, int[] numConfigs) { EGLConfig[] configs = new EGLConfig[numConfigs[0]]; if (!egl.eglChooseConfig(display, configAttributes, configs, numConfigs[0], numConfigs)) { - Timber.e("eglChooseConfig() returned error %d", egl.eglGetError()); + Logger.e(TAG, String.format( + MapboxConstants.MAPBOX_LOCALE, "eglChooseConfig() returned error %d", egl.eglGetError()) + ); throw new EGLConfigException("eglChooseConfig() failed"); } return configs; @@ -254,11 +259,11 @@ public int compareTo(@NonNull Config other) { Config bestMatch = matches.get(0); if (bestMatch.isCaveat) { - Timber.w("Chosen config has a caveat."); + Logger.w(TAG, "Chosen config has a caveat."); } if (bestMatch.isNotConformant) { - Timber.w("Chosen config is not conformant."); + Logger.w(TAG, "Chosen config is not conformant."); } return bestMatch.config; @@ -267,7 +272,9 @@ public int compareTo(@NonNull Config other) { private int getConfigAttr(EGL10 egl, EGLDisplay display, EGLConfig config, int attributeName) { int[] attributevalue = new int[1]; if (!egl.eglGetConfigAttrib(display, config, attributeName, attributevalue)) { - Timber.e("eglGetConfigAttrib(%d) returned error %d", attributeName, egl.eglGetError()); + Logger.e(TAG, String.format( + MapboxConstants.MAPBOX_LOCALE, "eglGetConfigAttrib(%d) returned error %d", attributeName, egl.eglGetError()) + ); throw new EGLConfigException("eglGetConfigAttrib() failed"); } return attributevalue[0]; @@ -275,7 +282,7 @@ private int getConfigAttr(EGL10 egl, EGLDisplay display, EGLConfig config, int a private int[] getConfigAttributes() { boolean emulator = inEmulator() || inGenymotion(); - Timber.i("In emulator: %s", emulator); + Logger.i(TAG, String.format("In emulator: %s", emulator)); // Get all configs at least RGB 565 with 16 depth and 8 stencil return new int[] { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java index 4bba160993d..0c7c16bad2f 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/textureview/TextureViewRenderThread.java @@ -4,11 +4,9 @@ import android.support.annotation.NonNull; import android.support.annotation.UiThread; import android.view.TextureView; +import com.mapbox.mapboxsdk.log.Logger; import com.mapbox.mapboxsdk.maps.renderer.egl.EGLConfigChooser; -import java.lang.ref.WeakReference; -import java.util.ArrayList; - import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGL11; import javax.microedition.khronos.egl.EGLConfig; @@ -16,8 +14,8 @@ import javax.microedition.khronos.egl.EGLDisplay; import javax.microedition.khronos.egl.EGLSurface; import javax.microedition.khronos.opengles.GL10; - -import timber.log.Timber; +import java.lang.ref.WeakReference; +import java.util.ArrayList; /** * The render thread is responsible for managing the communication between the @@ -26,6 +24,8 @@ */ class TextureViewRenderThread extends Thread implements TextureView.SurfaceTextureListener { + private static final String TAG = "TextureViewRenderThread"; + private final TextureViewMapRenderer mapRenderer; private final EGLHolder eglHolder; @@ -286,7 +286,7 @@ public void run() { case EGL10.EGL_SUCCESS: break; case EGL11.EGL_CONTEXT_LOST: - Timber.w("Context lost. Waiting for re-aquire"); + Logger.w(TAG, "Context lost. Waiting for re-aquire"); synchronized (lock) { surface = null; destroySurface = true; @@ -294,7 +294,7 @@ public void run() { } break; default: - Timber.w("eglSwapBuffer error: %s. Waiting or new surface", swapError); + Logger.w(TAG, String.format("eglSwapBuffer error: %s. Waiting or new surface", swapError)); // Probably lost the surface. Clear the current one and // wait for a new one to be set synchronized (lock) { @@ -390,7 +390,7 @@ boolean createSurface() { if (eglSurface == null || eglSurface == EGL10.EGL_NO_SURFACE) { int error = egl.eglGetError(); if (error == EGL10.EGL_BAD_NATIVE_WINDOW) { - Timber.e("createWindowSurface returned EGL_BAD_NATIVE_WINDOW."); + Logger.e(TAG, "createWindowSurface returned EGL_BAD_NATIVE_WINDOW."); } return false; } @@ -402,7 +402,7 @@ boolean makeCurrent() { if (!egl.eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext)) { // Could not make the context current, probably because the underlying // SurfaceView surface has been destroyed. - Timber.w("eglMakeCurrent: %s", egl.eglGetError()); + Logger.w(TAG, String.format("eglMakeCurrent: %s", egl.eglGetError())); return false; } @@ -422,7 +422,7 @@ private void destroySurface() { } if (!egl.eglDestroySurface(eglDisplay, eglSurface)) { - Timber.w("Could not destroy egl surface. Display %s, Surface %s", eglDisplay, eglSurface); + Logger.w(TAG, String.format("Could not destroy egl surface. Display %s, Surface %s", eglDisplay, eglSurface)); } eglSurface = EGL10.EGL_NO_SURFACE; @@ -434,7 +434,7 @@ private void destroyContext() { } if (!egl.eglDestroyContext(eglDisplay, eglContext)) { - Timber.w("Could not destroy egl context. Display %s, Context %s", eglDisplay, eglContext); + Logger.w(TAG, String.format("Could not destroy egl context. Display %s, Context %s", eglDisplay, eglContext)); } eglContext = EGL10.EGL_NO_CONTEXT; @@ -446,7 +446,7 @@ private void terminate() { } if (!egl.eglTerminate(eglDisplay)) { - Timber.w("Could not terminate egl. Display %s", eglDisplay); + Logger.w(TAG, String.format("Could not terminate egl. Display %s", eglDisplay)); } eglDisplay = EGL10.EGL_NO_DISPLAY; } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/ConnectivityReceiver.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/ConnectivityReceiver.java index 817dcdb4384..cb904b13c97 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/ConnectivityReceiver.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/ConnectivityReceiver.java @@ -9,19 +9,20 @@ import android.net.NetworkInfo; import android.support.annotation.NonNull; import android.support.annotation.UiThread; - import com.mapbox.mapboxsdk.Mapbox; +import com.mapbox.mapboxsdk.log.Logger; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; -import timber.log.Timber; - /** * Interface definition for a callback to be invoked when connectivity changes. * Not public api. */ public class ConnectivityReceiver extends BroadcastReceiver { + + private static final String TAG = "ConnectivityReceiver"; + @SuppressLint("StaticFieldLeak") private static ConnectivityReceiver INSTANCE; @@ -84,7 +85,7 @@ public void deactivate() { @Override public void onReceive(Context context, Intent intent) { boolean connected = isConnected(context); - Timber.v("Connected: %s", connected); + Logger.v(TAG, String.format("Connected: %s", connected)); // Loop over listeners for (ConnectivityListener listener : listeners) { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java index f2faabd63b1..3a8e03116e6 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java @@ -5,23 +5,23 @@ import android.os.Handler; import android.os.Looper; import android.support.annotation.NonNull; - import com.mapbox.mapboxsdk.LibraryLoader; import com.mapbox.mapboxsdk.R; import com.mapbox.mapboxsdk.geometry.LatLngBounds; +import com.mapbox.mapboxsdk.log.Logger; import com.mapbox.mapboxsdk.net.ConnectivityReceiver; import com.mapbox.mapboxsdk.storage.FileSource; import java.io.File; -import timber.log.Timber; - /** * The offline manager is the main entry point for offline-related functionality. * It'll help you list and create offline regions. */ public class OfflineManager { + private final static String TAG = "OfflineManager"; + // // Static methods // @@ -109,10 +109,10 @@ public void run() { File file = new File(path); if (file.exists()) { file.delete(); - Timber.d("Old ambient cache database deleted to save space: %s", path); + Logger.d(TAG, String.format("Old ambient cache database deleted to save space: %s", path)); } } catch (Exception exception) { - Timber.e(exception, "Failed to delete old ambient cache database: "); + Logger.e(TAG, "Failed to delete old ambient cache database: ", exception); } } }).start(); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java index a2c7ed5dfd9..b20feeea3f9 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java @@ -23,9 +23,9 @@ import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.constants.Style; import com.mapbox.mapboxsdk.geometry.LatLngBounds; +import com.mapbox.mapboxsdk.log.Logger; import com.mapbox.mapboxsdk.storage.FileSource; import com.mapbox.mapboxsdk.utils.ThreadUtils; -import timber.log.Timber; /** * The map snapshotter creates a large of the map, rendered @@ -35,6 +35,8 @@ @UiThread public class MapSnapshotter { + private static final String TAG = "MapSnapshotter"; + /** * Get notified on snapshot completion. * @@ -350,9 +352,10 @@ private void drawAttribution(MapSnapshot mapSnapshot, Canvas canvas, drawAttribution(canvas, measure, anchorPoint); } else { Bitmap snapshot = mapSnapshot.getBitmap(); - Timber.e("Could not generate attribution for snapshot size: %s x %s." + Logger.e(TAG, String.format("Could not generate attribution for snapshot size: %s x %s." + " You are required to provide your own attribution for the used sources: %s", - snapshot.getWidth(), snapshot.getHeight(), mapSnapshot.getAttributions()); + snapshot.getWidth(), snapshot.getHeight(), mapSnapshot.getAttributions()) + ); } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java index 929e4b42797..6f18623f919 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java @@ -7,10 +7,9 @@ import android.os.Environment; import android.support.annotation.NonNull; import android.support.annotation.UiThread; - import com.mapbox.mapboxsdk.Mapbox; import com.mapbox.mapboxsdk.constants.MapboxConstants; -import timber.log.Timber; +import com.mapbox.mapboxsdk.log.Logger; /** * Holds a central reference to the core's DefaultFileSource for as long as @@ -18,6 +17,8 @@ */ public class FileSource { + private static final String TAG = "FileSource"; + /** * This callback allows implementors to transform URLs before they are requested * from the internet. This can be used add or remove custom parameters, or reroute @@ -73,9 +74,9 @@ public static String getCachePath(Context context) { MapboxConstants.KEY_META_DATA_SET_STORAGE_EXTERNAL, MapboxConstants.DEFAULT_SET_STORAGE_EXTERNAL); } catch (PackageManager.NameNotFoundException exception) { - Timber.e(exception, "Failed to read the package metadata: "); + Logger.e(TAG, "Failed to read the package metadata: ", exception); } catch (Exception exception) { - Timber.e(exception, "Failed to read the storage key: "); + Logger.e(TAG, "Failed to read the storage key: ", exception); } String cachePath = null; @@ -84,7 +85,7 @@ public static String getCachePath(Context context) { // Try getting the external storage path cachePath = context.getExternalFilesDir(null).getAbsolutePath(); } catch (NullPointerException exception) { - Timber.e(exception, "Failed to obtain the external storage path: "); + Logger.e(TAG, "Failed to obtain the external storage path: ", exception); } } @@ -112,7 +113,7 @@ public static boolean isExternalStorageReadable() { return true; } - Timber.w("External storage was requested but it isn't readable. For API level < 18" + Logger.w(TAG, "External storage was requested but it isn't readable. For API level < 18" + " make sure you've requested READ_EXTERNAL_STORAGE or WRITE_EXTERNAL_STORAGE" + " permissions in your app Manifest (defaulting to internal storage)."); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyValue.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyValue.java index fa1779a6c75..44e33fcd873 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyValue.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyValue.java @@ -3,19 +3,19 @@ import android.support.annotation.ColorInt; import android.support.annotation.NonNull; import android.support.annotation.Nullable; - import com.google.gson.JsonArray; import com.mapbox.mapboxsdk.exceptions.ConversionException; +import com.mapbox.mapboxsdk.log.Logger; import com.mapbox.mapboxsdk.style.expressions.Expression; import com.mapbox.mapboxsdk.utils.ColorUtils; -import timber.log.Timber; - /** * Properties for Layer */ public class PropertyValue { + private static final String TAG = "PropertyValue"; + public final String name; public final T value; @@ -59,7 +59,7 @@ public Expression getExpression() { if (isExpression()) { return Expression.Converter.convert((JsonArray) value); } else { - Timber.w("not a expression, try value"); + Logger.w(TAG, "not a expression, try value"); return null; } } @@ -84,7 +84,7 @@ public T getValue() { // noinspection unchecked return value; } else { - Timber.w("not a value, try function"); + Logger.w(TAG, "not a value, try function"); return null; } } @@ -98,14 +98,14 @@ public T getValue() { @Nullable public Integer getColorInt() { if (!isValue() || !(value instanceof String)) { - Timber.e("%s is not a String value and can not be converted to a color it", name); + Logger.e(TAG, String.format("%s is not a String value and can not be converted to a color it", name)); return null; } try { return ColorUtils.rgbaToColor((String) value); } catch (ConversionException ex) { - Timber.e("%s could not be converted to a Color int: %s", name, ex.getMessage()); + Logger.e(TAG, String.format("%s could not be converted to a Color int: %s", name, ex.getMessage())); return null; } } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle index d21eb73382d..50660a8c527 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 + implementation(project(':MapboxGLAndroidSDK')) { + exclude module: 'MapboxGLAndroidModuleHttp' + } + + 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/http/HttpRequestImpl.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestImpl.java new file mode 100644 index 00000000000..1653e1394e1 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestImpl.java @@ -0,0 +1,39 @@ +package com.mapbox.mapboxsdk.http; + +import com.koushikdutta.async.future.Future; +import com.koushikdutta.ion.Ion; +import com.koushikdutta.ion.Response; +import com.koushikdutta.ion.builder.Builders; +import com.mapbox.mapboxsdk.Mapbox; + +import java.util.concurrent.ExecutionException; + +public class HttpRequestImpl extends HttpRequest { + + @Override + public void executeRequest(HttpRequestResponder httpRequest, long nativePtr, String resourceUrl, + String etag, String modified) { + Builders.Any.B loadBuilder = Ion.with(Mapbox.getApplicationContext()).load(resourceUrl); + if (etag.length() > 0) { + loadBuilder.addHeader("If-None-Match", etag); + } else if (modified.length() > 0) { + loadBuilder.addHeader("If-Modified-Since", modified); + } + Future> future = loadBuilder.asByteArray().withResponse(); + try { + Response 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() { + // do nothing + // TODO manage Future objects and execute Future#cancel + } +} 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 a06a4893887..2060d576750 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,11 @@ 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.testapp.utils.TokenUtils; import com.squareup.leakcanary.LeakCanary; + import timber.log.Timber; import static timber.log.Timber.DebugTree; @@ -70,7 +71,7 @@ private void initializeMapbox() { String accessToken = TokenUtils.getMapboxAccessToken(getApplicationContext()); validateAccessToken(accessToken); Mapbox.getInstance(getApplicationContext(), accessToken); - Telemetry.updateDebugLoggingEnabled(true); + //TelemetryBase.updateDebugLoggingEnabled(true); } private static void validateAccessToken(String accessToken) { diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/LatLngBoundsActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/LatLngBoundsActivity.java index ac4c6ff9df7..686f564c5c0 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/LatLngBoundsActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/LatLngBoundsActivity.java @@ -10,7 +10,6 @@ import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.geometry.LatLngBounds; -import com.mapbox.mapboxsdk.http.HttpRequestUtil; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.testapp.R; @@ -52,7 +51,6 @@ public class LatLngBoundsActivity extends AppCompatActivity implements View.OnCl @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - HttpRequestUtil.setLogEnabled(false); setContentView(R.layout.activity_latlngbounds); mapView = (MapView) findViewById(R.id.mapView); mapView.onCreate(savedInstanceState); @@ -151,7 +149,6 @@ public void onLowMemory() { protected void onDestroy() { super.onDestroy(); mapView.onDestroy(); - HttpRequestUtil.setLogEnabled(true); } @Override diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DebugModeActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DebugModeActivity.java index 44d27a41abd..22da952560c 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DebugModeActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/DebugModeActivity.java @@ -16,7 +16,6 @@ import android.widget.TextView; import com.mapbox.mapboxsdk.constants.Style; -import com.mapbox.mapboxsdk.http.HttpRequestUtil; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; @@ -55,7 +54,6 @@ public class DebugModeActivity extends AppCompatActivity implements OnMapReadyCa @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - HttpRequestUtil.setPrintRequestUrlOnFailure(true); setContentView(R.layout.activity_debug_mode); setupToolbar(); setupMapView(savedInstanceState); @@ -206,7 +204,6 @@ protected void onSaveInstanceState(Bundle outState) { protected void onDestroy() { super.onDestroy(); mapView.onDestroy(); - HttpRequestUtil.setPrintRequestUrlOnFailure(false); } @Override diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java index 79e76168d5c..4604d20b8a7 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/offline/OfflineActivity.java @@ -70,7 +70,7 @@ protected void onCreate(Bundle savedInstanceState) { // You can use Mapbox.setConnected(Boolean) to manually set the connectivity // state of your app. This will override any checks performed via the ConnectivityManager. - // Mapbox.getInstance().setConnected(false); + // Mapbox.initialize().setConnected(false); Boolean connected = Mapbox.isConnected(); Timber.d("Mapbox is connected: %s", connected); 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 e3c5254805a..6c37f3d5ea4 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.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.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 @@ protected void onPostExecute(List renderTestDefinitions) { private static List loadIgnoreList(AssetManager assets) { List 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 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 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 @@ private static List loadIgnoreList(AssetManager assets) { 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/config.cmake b/platform/android/config.cmake index 21ec6a9e0ca..cfa1ef54267 100644 --- a/platform/android/config.cmake +++ b/platform/android/config.cmake @@ -73,6 +73,10 @@ macro(mbgl_platform_core) PRIVATE platform/default/mbgl/map/map_snapshotter.cpp PRIVATE platform/default/mbgl/map/map_snapshotter.hpp PRIVATE platform/linux/src/headless_backend_egl.cpp + + # Logger + PRIVATE platform/android/src/logger.cpp + PRIVATE platform/android/src/logger.hpp ) target_include_directories(mbgl-core diff --git a/platform/android/MapboxGLAndroidSDK/gradle.properties b/platform/android/gradle.properties similarity index 100% rename from platform/android/MapboxGLAndroidSDK/gradle.properties rename to platform/android/gradle.properties diff --git a/platform/android/gradle/dependencies.gradle b/platform/android/gradle/dependencies.gradle index fccaea9f719..01b92fe1c64 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/gradle/gradle-checkstyle.gradle b/platform/android/gradle/gradle-checkstyle.gradle index 41a68f90ce3..8eb4baa858d 100644 --- a/platform/android/gradle/gradle-checkstyle.gradle +++ b/platform/android/gradle/gradle-checkstyle.gradle @@ -18,7 +18,9 @@ task checkstyle(type: Checkstyle) { exclude '**/style/layers/PropertyFactory.java' exclude '**/style/layers/*Layer.java' exclude '**/style/light/Light.java' - exclude '**/Expression.java' // allowing single character signature as e() + exclude '**/log/LoggerDefinition.java' + exclude '**/log/Logger.java' + exclude '**/Expression.java' classpath = files() ignoreFailures = false } diff --git a/platform/android/settings.gradle b/platform/android/settings.gradle index b5ab80b5ec3..44b0ab27c84 100644 --- a/platform/android/settings.gradle +++ b/platform/android/settings.gradle @@ -1 +1 @@ -include ':MapboxGLAndroidSDK', ':MapboxGLAndroidSDKTestApp' \ No newline at end of file +include ':MapboxGLAndroidSDK', ':MapboxGLAndroidSDKTestApp', ':MapboxGLAndroidModuleBase', ':MapboxGLAndroidModuleHttp', ':MapboxGLAndroidModuleTelemetry' \ No newline at end of file diff --git a/platform/android/src/http_file_source.cpp b/platform/android/src/http_file_source.cpp index cda84209ea3..fc7ffbec8c1 100644 --- a/platform/android/src/http_file_source.cpp +++ b/platform/android/src/http_file_source.cpp @@ -20,7 +20,7 @@ class HTTPFileSource::Impl { 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(); diff --git a/platform/android/src/jni.cpp b/platform/android/src/jni.cpp index beb2c14eb3e..f1d693ea109 100755 --- a/platform/android/src/jni.cpp +++ b/platform/android/src/jni.cpp @@ -49,6 +49,7 @@ #include "text/collator_jni.hpp" #include "text/local_glyph_rasterizer_jni.hpp" #include "java/lang.hpp" +#include "logger.hpp" namespace mbgl { namespace android { @@ -191,6 +192,9 @@ void registerNatives(JavaVM *vm) { LocalGlyphRasterizer::registerNative(env); Locale::registerNative(env); Collator::registerNative(env); + + // Logger + Logger::registerNative(env); } } // namespace android diff --git a/platform/android/src/logger.cpp b/platform/android/src/logger.cpp new file mode 100644 index 00000000000..18a390b3e61 --- /dev/null +++ b/platform/android/src/logger.cpp @@ -0,0 +1,34 @@ +#include "logger.hpp" +#include "java_types.hpp" + +namespace mbgl { +namespace android { + +void Logger::registerNative(jni::JNIEnv& env) { + _class = *jni::Class::Find(env).NewGlobalRef(env).release(); +} + +jni::Class Logger::_class; + +void Logger::log(jni::JNIEnv& env, EventSeverity severity, const std::string &msg) { + auto tag = jni::Make(env, "MBGL"); + auto message = jni::Make(env, msg); + using Signature = void(jni::String, jni::String); + + if(severity == EventSeverity::Debug){ + auto method = _class.GetStaticMethod(env, "d"); + _class.Call(env, method, tag, message); + }else if(severity == EventSeverity::Info){ + auto method = _class.GetStaticMethod(env, "i"); + _class.Call(env, method, tag, message); + }else if(severity == EventSeverity::Warning){ + auto method = _class.GetStaticMethod(env, "w"); + _class.Call(env, method, tag, message); + }else{ + auto method = _class.GetStaticMethod(env, "e"); + _class.Call(env, method, tag, message); + } +} + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/logger.hpp b/platform/android/src/logger.hpp new file mode 100644 index 00000000000..d4805fccd8c --- /dev/null +++ b/platform/android/src/logger.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include +#include +#include "bitmap.hpp" + +namespace mbgl { +namespace android { + +class Logger { +public: + static constexpr auto Name() { + return "com/mapbox/mapboxsdk/log/Logger"; + }; + static void registerNative(jni::JNIEnv&); + + static void log(jni::JNIEnv&, EventSeverity severity, const std::string &msg); + +private: + static jni::Class _class; +}; + +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/logging_android.cpp b/platform/android/src/logging_android.cpp index 2e025c059fb..1301367280c 100644 --- a/platform/android/src/logging_android.cpp +++ b/platform/android/src/logging_android.cpp @@ -1,34 +1,13 @@ #include -#include +#include "logger.hpp" +#include "attach_env.hpp" namespace mbgl { -namespace { - -int severityToPriority(EventSeverity severity) { - switch(severity) { - case EventSeverity::Debug: - return ANDROID_LOG_DEBUG; - - case EventSeverity::Info: - return ANDROID_LOG_INFO; - - case EventSeverity::Warning: - return ANDROID_LOG_WARN; - - case EventSeverity::Error: - return ANDROID_LOG_ERROR; - - default: - return ANDROID_LOG_VERBOSE; - } -} - -} // namespace - void Log::platformRecord(EventSeverity severity, const std::string &msg) { - __android_log_print(severityToPriority(severity), "mbgl", "%s", msg.c_str()); + auto env{ android::AttachEnv() }; + android::Logger::log(*env, severity, msg); } -} +} \ No newline at end of file