Skip to content

Commit

Permalink
Add new User Agent:
Browse files Browse the repository at this point in the history
Spec: mapbox/mobile-telemetry#423
Add new User agent with header X-Mapbox-User-Agent in addition to current user agent.
The new user agent is constructed from host app and Mapbox libraries version information.
Update the version for android-sdk-versions-plugin.
Update copyright year to 2018-2019 in LICENSE.MD
Change publishing license from "The Apache Software License, Version 2.0" to "The MIT License" for consistency.
  • Loading branch information
Harsha Sura committed Nov 22, 2019
1 parent f79dbfd commit f697df1
Show file tree
Hide file tree
Showing 23 changed files with 357 additions and 74 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ Mapbox welcomes participation and contributions from everyone.

## Mapbox Android Telemetry

## v4.6.1
- Fix crash `setBaseUrl()` on null `TelemetryClient` [#423](https://github.com/mapbox/mapbox-events-android/pull/423)

## v4.6.0
- Add public api to change base url for telemetry endpoint [#420](https://github.com/mapbox/mapbox-events-android/pull/420)
- Telemetry metrics [#397](https://github.com/mapbox/mapbox-events-android/pull/397)
Expand Down
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2018 Mapbox
Copyright (c) 2018-2019 Mapbox

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
4 changes: 2 additions & 2 deletions gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ POM_SCM_URL=https://github.com/mapbox/mapbox-events-android
POM_SCM_CONNECTION=scm:[email protected]:mapbox/mapbox-events-android.git
POM_SCM_DEV_CONNECTION=scm:[email protected]:mapbox/mapbox-events-android.git

POM_LICENCE_NAME=The Apache Software License, Version 2.0
POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
POM_LICENCE_NAME=The MIT License
POM_LICENCE_URL=https://opensource.org/licenses/MIT
POM_LICENCE_DIST=repo

POM_DEVELOPER_ID=mapbox
Expand Down
2 changes: 1 addition & 1 deletion gradle/dependencies.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ ext {
checkstyle : '8.4',
gradle : '3.4.1',
dependencyGraph : '0.5.0',
mapboxSdkVersions: '0.1.3'
mapboxSdkVersions: '1.0.1'
]

dependenciesList = [
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.mapbox.android.core;

import android.content.Context;
import android.support.test.InstrumentationRegistry;

import org.junit.Assert;
import org.junit.Test;

import java.util.Locale;

public class UserAgentSDKInfoTest {

private static final String SDK_UA_FORMAT = "%s/%s (%s; %s)";
private static final String SDK_UA_VERSION_CODE_FORMAT = "v%d";
private static final Locale LOCALE_DEFAULT = Locale.US;
private static final String NAME = "libcore";

@Test
public void testSDKInformation() {
Context context = InstrumentationRegistry.getContext();
String packageName = context.getPackageName().replace(".test", "");
String versionCode = String.format(LOCALE_DEFAULT, SDK_UA_VERSION_CODE_FORMAT, BuildConfig.VERSION_CODE);
String sdkInfo = MapboxSdkInfoForUserAgentGenerator.getInstance(context.getAssets())
.getMapboxSdkIdentifiersForUserAgent(context.getAssets());
Assert.assertEquals(String.format(Locale.US, SDK_UA_FORMAT, NAME, BuildConfig.VERSION_NAME,
packageName, versionCode), sdkInfo);
}

@Test
public void testUserAgentSdkInfo() {
Context context = InstrumentationRegistry.getContext();
String sdkInfo = MapboxSdkInfoForUserAgentGenerator.getInstance(context.getAssets())
.getSdkInfoForUserAgent();
String packageName = context.getPackageName().replace(".test", "");
String versionCode = String.format(LOCALE_DEFAULT, SDK_UA_VERSION_CODE_FORMAT, BuildConfig.VERSION_CODE);
Assert.assertEquals(String.format(Locale.US, SDK_UA_FORMAT, NAME, BuildConfig.VERSION_NAME,
packageName, versionCode), sdkInfo);
}

@Test(expected = NullPointerException.class)
public void testSDKInformationInUserAgentWithNullContext() {
MapboxSdkInfoForUserAgentGenerator.getInstance(null)
.getSdkInfoForUserAgent();

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package com.mapbox.android.core;

import android.content.res.AssetManager;
import android.support.annotation.NonNull;
import android.support.annotation.RestrictTo;
import android.support.annotation.VisibleForTesting;
import android.util.Log;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Locale;

/**
* Generator that reads(from assets/sdk_versions folder) and constructs Mapbox SDK versions for user agent.
* Generates strings in format for each Mapbox library in the host app and concatenates them seperated by spaces.
* <p> User agent format for Mapbox SDK : {SDK Name}/{Version} ({packageName}; {versionCode}) </p>
*/
public class MapboxSdkInfoForUserAgentGenerator {

private static MapboxSdkInfoForUserAgentGenerator userAgentGenerator;

private String sdkInfoForUserAgent;
private static final Object lock = new Object();
private static final Locale DEFAULT_LOCALE = Locale.US;
private static final String USER_AGENT_SDK_VERSION_FORMAT = " %s (%s%s)";
private static final String MAPBOX_IDENTIFIER = "mapbox";
private static final String EMPTY_STRING = "";
private static final String SDK_VERSIONS_FOLDER = "sdk_versions";
private static final String LOG_TAG = "MapboxUAGenerator";

private MapboxSdkInfoForUserAgentGenerator(AssetManager assetManager) {
this.sdkInfoForUserAgent = getMapboxSdkIdentifiersForUserAgent(assetManager);
}

public static MapboxSdkInfoForUserAgentGenerator getInstance(@NonNull AssetManager assetManager) {
if (userAgentGenerator == null) {
synchronized (lock) {
userAgentGenerator = new MapboxSdkInfoForUserAgentGenerator(assetManager);
}
}
return userAgentGenerator;
}

@VisibleForTesting
@RestrictTo(RestrictTo.Scope.LIBRARY)
String getMapboxSdkIdentifiersForUserAgent(@NonNull AssetManager assetManager) {
StringBuilder stringBuilder = new StringBuilder(EMPTY_STRING);
try {
String[] files = assetManager.list(SDK_VERSIONS_FOLDER);
if (files != null) {
for (String fileName : files) {
if (fileName.contains(MAPBOX_IDENTIFIER)) {
InputStream inputStream = null;
try {
inputStream = assetManager.open(SDK_VERSIONS_FOLDER + File.separator + fileName);
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String nameAndVersion = reader.readLine();
nameAndVersion = nameAndVersion != null ? nameAndVersion : EMPTY_STRING;
StringBuilder sdkSubInfo = new StringBuilder(EMPTY_STRING);
String subInfo;
while ((subInfo = reader.readLine()) != null) {
sdkSubInfo.append("; ");
sdkSubInfo.append(subInfo);
}
reader.close();
stringBuilder.append(String.format(DEFAULT_LOCALE, USER_AGENT_SDK_VERSION_FORMAT,
nameAndVersion, fileName, sdkSubInfo.toString()));
} catch (IOException exception) {
Log.e(LOG_TAG, exception.toString());
} finally {
FileUtils.closeQuietly(inputStream);
}
}
}
}
} catch (IOException exception) {
Log.e(LOG_TAG, exception.toString());
}
return stringBuilder.toString().trim();
}

public String getSdkInfoForUserAgent() {
return sdkInfoForUserAgent;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.mapbox.android.core;

import android.content.res.AssetManager;

import org.junit.Test;

import java.io.IOException;

import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class UserAgentSDKInfoHandleExceptionsTest {

@Test
public void testSDKInformationCatchOpenAssetsIOException() throws Exception {
AssetManager assetManager = mock(AssetManager.class);
when(assetManager.list(anyString())).thenThrow(IOException.class);
MapboxSdkInfoForUserAgentGenerator.getInstance(assetManager)
.getSdkInfoForUserAgent();
}

@Test
public void testSDKInformationReadInputStremIOException() throws IOException {
AssetManager assetManager = mock(AssetManager.class);
when(assetManager.list(anyString())).thenReturn(new String[] {"com.mapbox.android.core"});
when(assetManager.open(anyString())).thenThrow(IOException.class);
MapboxSdkInfoForUserAgentGenerator.getInstance(assetManager)
.getSdkInfoForUserAgent();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ public void requestLocationUpdates(@NonNull LocationEngineRequest request,
@Nullable Looper looper) throws SecurityException {
// Pick best provider only if user has not explicitly chosen passive mode
currentProvider = getBestProvider(request.getPriority());
locationManager.requestLocationUpdates(currentProvider, request.getInterval(), request.getDisplacemnt(),
locationManager.requestLocationUpdates(currentProvider, request.getInterval(), request.getDisplacement(),
listener, looper);
}

Expand All @@ -82,7 +82,7 @@ public void requestLocationUpdates(@NonNull LocationEngineRequest request,
// Pick best provider only if user has not explicitly chosen passive mode
currentProvider = getBestProvider(request.getPriority());
locationManager.requestLocationUpdates(currentProvider, request.getInterval(),
request.getDisplacemnt(), pendingIntent);
request.getDisplacement(), pendingIntent);
}

@SuppressLint("MissingPermission")
Expand Down Expand Up @@ -171,4 +171,4 @@ public void onProviderDisabled(String s) {
callback.onFailure(new Exception("Current provider disabled"));
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ private static LocationRequest toGMSLocationRequest(LocationEngineRequest reques
LocationRequest locationRequest = new LocationRequest();
locationRequest.setInterval(request.getInterval());
locationRequest.setFastestInterval(request.getFastestInterval());
locationRequest.setSmallestDisplacement(request.getDisplacemnt());
locationRequest.setSmallestDisplacement(request.getDisplacement());
locationRequest.setMaxWaitTime(request.getMaxWaitTime());
locationRequest.setPriority(toGMSLocationPriority(request.getPriority()));
return locationRequest;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public int getPriority() {
* @return distance between location updates in meters.
* @since 1.0.0
*/
public float getDisplacemnt() {
public float getDisplacement() {
return displacement;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public void requestLocationUpdates(@NonNull LocationEngineRequest request,
if (shouldStartNetworkProvider(request.getPriority())) {
try {
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER,
request.getInterval(), request.getDisplacemnt(),
request.getInterval(), request.getDisplacement(),
listener, looper);
} catch (IllegalArgumentException iae) {
iae.printStackTrace();
Expand All @@ -71,7 +71,7 @@ public void requestLocationUpdates(@NonNull LocationEngineRequest request,
if (shouldStartNetworkProvider(request.getPriority())) {
try {
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, request.getInterval(),
request.getDisplacemnt(), pendingIntent);
request.getDisplacement(), pendingIntent);
} catch (IllegalArgumentException iae) {
iae.printStackTrace();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.mapbox.android.telemetry;

import android.content.Context;
import android.support.test.InstrumentationRegistry;

import org.junit.Assert;
import org.junit.Test;

public class TestReformedUserAgent {

private static final String CORE_PACKAGE = "com.mapbox.android.core";
private static final String TELEMETRY_PACKAGE = "com.mapbox.android.telemetry";

@Test
public void testReformedUserAgent() {
Context context = InstrumentationRegistry.getContext();
String reformedUserAgent = TelemetryUtils.createReformedFullUserAgent(context);
Assert.assertTrue(reformedUserAgent.contains(context.getPackageName()));
Assert.assertTrue(reformedUserAgent.contains(CORE_PACKAGE));
Assert.assertTrue(reformedUserAgent.contains(TELEMETRY_PACKAGE));
Assert.assertFalse(reformedUserAgent.contains("null"));
}

@Test(expected = NullPointerException.class)
public void testReformedUserAgentForNullContext() {
TelemetryUtils.createReformedFullUserAgent(null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -479,10 +479,12 @@ public Thread newThread(Runnable runnable) {
}

@SuppressWarnings("WeakerAccess")
public void setBaseUrl(String eventsHost) {
if (isValidUrl(eventsHost)) {
public synchronized boolean setBaseUrl(String eventsHost) {
if (isValidUrl(eventsHost) && checkNetworkAndParameters()) {
telemetryClient.setBaseUrl(eventsHost);
return true;
}
return false;
}

private static boolean isValidUrl(String eventsHost) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.mapbox.android.telemetry;

import android.content.Context;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -28,7 +29,7 @@ public MapboxTelemetry(Context context, String accessToken, String userAgent) {
initializeContext(context);
// FIXME: Propagate certificate blacklist changes from full version
this.configurationClient = new ConfigurationClient(context, TelemetryUtils.createFullUserAgent(userAgent,
context), accessToken, new OkHttpClient());
context), accessToken, new OkHttpClient());
this.certificateBlacklist = new CertificateBlacklist(context, configurationClient);
checkRequiredParameters(accessToken, userAgent);
initializeTelemetryListeners();
Expand All @@ -46,7 +47,7 @@ public MapboxTelemetry(Context context, String accessToken, String userAgent) {
this.httpCallback = httpCallback;
initializeTelemetryListeners();
this.configurationClient = new ConfigurationClient(context, TelemetryUtils.createFullUserAgent(userAgent,
context), accessToken, new OkHttpClient());
context), accessToken, new OkHttpClient());
this.certificateBlacklist = new CertificateBlacklist(context, configurationClient);
}

Expand Down Expand Up @@ -165,6 +166,7 @@ private void initializeTelemetryClient() {

private TelemetryClient createTelemetryClient(String accessToken, String userAgent) {
String fullUserAgent = TelemetryUtils.createFullUserAgent(userAgent, applicationContext);

TelemetryClientFactory telemetryClientFactory = new TelemetryClientFactory(accessToken, fullUserAgent,
new Logger(), certificateBlacklist);
telemetryClient = telemetryClientFactory.obtainTelemetryClient(applicationContext);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,24 @@ class TelemetryClient {
private static final String EVENTS_ENDPOINT = "/events/v2";
private static final String ATTACHMENTS_ENDPOINT = "/attachments/v1";
private static final String USER_AGENT_REQUEST_HEADER = "User-Agent";
private static final String MAPBOX_AGENT_REQUEST_HEADER = "X-Mapbox-Agent";
private static final String ACCESS_TOKEN_QUERY_PARAMETER = "access_token";
private static final String EXTRA_DEBUGGING_LOG = "Sending POST to %s with %d event(s) (user agent: %s) "
+ "with payload: %s";
private static final String BOUNDARY = "--01ead4a5-7a67-4703-ad02-589886e00923";

private String accessToken;
private String userAgent;
private String reformedUserAgent;
private TelemetryClientSettings setting;
private final Logger logger;
private CertificateBlacklist certificateBlacklist;

TelemetryClient(String accessToken, String userAgent, TelemetryClientSettings setting, Logger logger,
CertificateBlacklist certificateBlacklist) {
TelemetryClient(String accessToken, String userAgent, String reformedUserAgent, TelemetryClientSettings setting,
Logger logger, CertificateBlacklist certificateBlacklist) {
this.accessToken = accessToken;
this.userAgent = userAgent;
this.reformedUserAgent = reformedUserAgent;
this.setting = setting;
this.logger = logger;
this.certificateBlacklist = certificateBlacklist;
Expand Down Expand Up @@ -96,6 +99,7 @@ void sendAttachment(Attachment attachment, final CopyOnWriteArraySet<AttachmentL
Request request = new Request.Builder()
.url(requestUrl)
.header(USER_AGENT_REQUEST_HEADER, userAgent)
.addHeader(MAPBOX_AGENT_REQUEST_HEADER, reformedUserAgent)
.post(requestBody)
.build();

Expand Down Expand Up @@ -147,6 +151,7 @@ private void sendBatch(List<Event> batch, Callback callback, boolean serializeNu
Request request = new Request.Builder()
.url(url)
.header(USER_AGENT_REQUEST_HEADER, userAgent)
.addHeader(MAPBOX_AGENT_REQUEST_HEADER, reformedUserAgent)
.post(body)
.build();

Expand Down
Loading

0 comments on commit f697df1

Please sign in to comment.