Skip to content
This repository has been archived by the owner on Aug 8, 2023. It is now read-only.

Commit

Permalink
[android] Introduce AccountsManager to support SKU tokens in API requ…
Browse files Browse the repository at this point in the history
…ests (#14404)
  • Loading branch information
zugaldia authored Apr 18, 2019
1 parent ec8cf0c commit d0a1526
Show file tree
Hide file tree
Showing 10 changed files with 174 additions and 9 deletions.
6 changes: 6 additions & 0 deletions platform/android/LICENSE.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ License: [Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt)

===========================================================================

Mapbox GL uses portions of the Mapbox Accounts SDK for Android.
URL: [https://github.com/mapbox/mapbox-accounts-android](https://github.com/mapbox/mapbox-accounts-android)
License: [Mapbox Terms of Service](https://www.mapbox.com/tos/)

===========================================================================

Mapbox GL uses portions of the Mapbox Android Core Library.
URL: [https://github.com/mapbox/mapbox-events-android](https://github.com/mapbox/mapbox-events-android)
License: [The Apache Software License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.txt)
Expand Down
1 change: 1 addition & 0 deletions platform/android/MapboxGLAndroidSDK/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ dependencies {
api dependenciesList.mapboxAndroidTelemetry
api dependenciesList.mapboxJavaGeoJSON
api dependenciesList.mapboxAndroidGestures
api dependenciesList.mapboxAndroidAccounts
implementation dependenciesList.mapboxJavaTurf
implementation dependenciesList.supportAnnotations
implementation dependenciesList.supportFragmentV4
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
package com.mapbox.mapboxsdk;

import android.content.Context;
import android.content.SharedPreferences;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.text.format.DateUtils;

import com.mapbox.android.accounts.v1.MapboxAccounts;
import com.mapbox.mapboxsdk.constants.MapboxConstants;

/**
* REMOVAL OR MODIFICATION OF THE FOLLOWING CODE VIOLATES THE MAPBOX TERMS
* OF SERVICE
*
* The following code is used to access Mapbox's Mapping APIs.
*
* Removal or modification of this code when used with Mapbox's Mapping APIs
* can result in termination of your agreement and/or your account with
* Mapbox.
*
* Using this code to access Mapbox Mapping APIs from outside the Mapbox Maps
* SDK also violates the Mapbox Terms of Service. On Android, Mapping APIs
* should be accessed using the methods documented at
* https://www.mapbox.com/android.
*
* You can access the Mapbox Terms of Service at https://www.mapbox.com/tos/
*/
class AccountsManager {
private static final String PREFERENCE_USER_ID = "com.mapbox.mapboxsdk.accounts.userid";
private static final String PREFERENCE_TIMESTAMP = "com.mapbox.mapboxsdk.accounts.timestamp";
private static final String PREFERENCE_SKU_TOKEN = "com.mapbox.mapboxsdk.accounts.skutoken";

private long timestamp;
private String skuToken;

AccountsManager() {
String userId = validateUserId();
validateRotation(userId);
}

private String validateUserId() {
SharedPreferences sharedPreferences = getSharedPreferences();
String userId = sharedPreferences.getString(PREFERENCE_USER_ID, "");
if (TextUtils.isEmpty(userId)) {
userId = generateUserId();
SharedPreferences.Editor editor = getSharedPreferences().edit();
editor.putString(PREFERENCE_USER_ID, userId);
editor.apply();
}

return userId;
}

private void validateRotation(String userId) {
SharedPreferences sharedPreferences = getSharedPreferences();
timestamp = sharedPreferences.getLong(PREFERENCE_TIMESTAMP, 0L);
skuToken = sharedPreferences.getString(PREFERENCE_SKU_TOKEN, "");
if (timestamp == 0L || TextUtils.isEmpty(skuToken)) {
skuToken = generateSkuToken(userId);
timestamp = persistRotation(skuToken);
}
}

String getSkuToken() {
if (isExpired()) {
SharedPreferences sharedPreferences = getSharedPreferences();
String userId = sharedPreferences.getString(PREFERENCE_USER_ID, "");
skuToken = generateSkuToken(userId);
timestamp = persistRotation(skuToken);
}

return skuToken;
}

private boolean isExpired() {
return isExpired(getNow(), timestamp);
}

static boolean isExpired(long now, long then) {
return ((now - then) > DateUtils.HOUR_IN_MILLIS);
}

private long persistRotation(String skuToken) {
long now = getNow();
SharedPreferences.Editor editor = getSharedPreferences().edit();
editor.putLong(PREFERENCE_TIMESTAMP, now);
editor.putString(PREFERENCE_SKU_TOKEN, skuToken);
editor.apply();
return now;
}

@NonNull
private SharedPreferences getSharedPreferences() {
return Mapbox.getApplicationContext()
.getSharedPreferences(MapboxConstants.MAPBOX_SHARED_PREFERENCES, Context.MODE_PRIVATE);
}

static long getNow() {
return System.currentTimeMillis();
}

@NonNull
private String generateUserId() {
return MapboxAccounts.obtainEndUserId();
}

@NonNull
private String generateSkuToken(String userId) {
return MapboxAccounts.obtainMapsSkuUserToken(userId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ public final class Mapbox {
private String accessToken;
@Nullable
private TelemetryDefinition telemetry;
@Nullable
private AccountsManager accounts;

/**
* Get an instance of Mapbox.
Expand All @@ -56,6 +58,7 @@ public static synchronized Mapbox getInstance(@NonNull Context context, @Nullabl
INSTANCE = new Mapbox(appContext, accessToken);
if (isAccessTokenValid(accessToken)) {
initializeTelemetry();
INSTANCE.accounts = new AccountsManager();
}
ConnectivityReceiver.instance(appContext);
}
Expand Down Expand Up @@ -87,6 +90,16 @@ public static void setAccessToken(String accessToken) {
FileSource.getInstance(getApplicationContext()).setAccessToken(accessToken);
}

/**
* Returns a SKU token, refreshed if necessary. This method is meant for internal SDK
* usage only.
*
* @return the SKU token
*/
public static String getSkuToken() {
return INSTANCE.accounts.getSkuToken();
}

/**
* Application context
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ public class MapboxConstants {
*/
public static final Locale MAPBOX_LOCALE = Locale.US;

/**
* The name of the desired preferences file for Android's SharedPreferences.
*/
public static final String MAPBOX_SHARED_PREFERENCES = "MapboxSharedPreferences";

/**
* Key used to switch storage to external in AndroidManifest.xml
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import android.support.annotation.NonNull;

import com.mapbox.mapboxsdk.Mapbox;

public class HttpRequestUrl {

private HttpRequestUrl() {
Expand All @@ -22,7 +24,7 @@ public static String buildResourceUrl(@NonNull String host, String resourceUrl,
} else {
resourceUrl = resourceUrl + "&";
}
resourceUrl = resourceUrl + "events=true";
resourceUrl = resourceUrl + "events=true&sku=" + Mapbox.getSkuToken();
}
return resourceUrl;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
import android.os.Bundle;
import android.support.annotation.FloatRange;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

import com.mapbox.android.accounts.v1.MapboxAccounts;
import com.mapbox.android.telemetry.AppUserTurnstile;
import com.mapbox.android.telemetry.MapboxTelemetry;
import com.mapbox.android.telemetry.SessionInterval;
Expand All @@ -21,9 +21,8 @@

public class TelemetryImpl implements TelemetryDefinition {

@Nullable
private MapboxTelemetry telemetry;
private Context appContext;
private final MapboxTelemetry telemetry;
private final Context appContext;

public TelemetryImpl() {
appContext = Mapbox.getApplicationContext();
Expand All @@ -42,6 +41,7 @@ public TelemetryImpl() {
public void onAppUserTurnstileEvent() {
AppUserTurnstile turnstileEvent = new AppUserTurnstile(BuildConfig.MAPBOX_SDK_IDENTIFIER,
BuildConfig.MAPBOX_SDK_VERSION);
turnstileEvent.setSkuId(MapboxAccounts.SKU_ID_MAPS_MAUS);
telemetry.push(turnstileEvent);
telemetry.push(MapEventFactory.buildMapLoadEvent(new PhoneState(appContext)));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
public class FileSource {

private static final String TAG = "Mbgl-FileSource";
private static final String MAPBOX_SHARED_PREFERENCES = "MapboxSharedPreferences";
private static final String MAPBOX_SHARED_PREFERENCE_RESOURCES_CACHE_PATH = "fileSourceResourcesCachePath";
private static final Lock resourcesCachePathLoaderLock = new ReentrantLock();
private static final Lock internalCachePathLoaderLock = new ReentrantLock();
Expand Down Expand Up @@ -107,7 +106,8 @@ public static synchronized FileSource getInstance(@NonNull Context context) {
*/
@NonNull
private static String getCachePath(@NonNull Context context) {
SharedPreferences preferences = context.getSharedPreferences(MAPBOX_SHARED_PREFERENCES, Context.MODE_PRIVATE);
SharedPreferences preferences = context.getSharedPreferences(
MapboxConstants.MAPBOX_SHARED_PREFERENCES, Context.MODE_PRIVATE);
String cachePath = preferences.getString(MAPBOX_SHARED_PREFERENCE_RESOURCES_CACHE_PATH, null);

if (!isPathWritable(cachePath)) {
Expand All @@ -116,7 +116,7 @@ private static String getCachePath(@NonNull Context context) {

// Reset stored cache path
SharedPreferences.Editor editor =
context.getSharedPreferences(MAPBOX_SHARED_PREFERENCES, Context.MODE_PRIVATE).edit();
context.getSharedPreferences(MapboxConstants.MAPBOX_SHARED_PREFERENCES, Context.MODE_PRIVATE).edit();
editor.remove(MAPBOX_SHARED_PREFERENCE_RESOURCES_CACHE_PATH).apply();
}

Expand Down Expand Up @@ -306,7 +306,7 @@ public void onWritePermissionGranted() {
callback.onError(fileSourceActivatedMessage);
} else {
final SharedPreferences.Editor editor =
context.getSharedPreferences(MAPBOX_SHARED_PREFERENCES, Context.MODE_PRIVATE).edit();
context.getSharedPreferences(MapboxConstants.MAPBOX_SHARED_PREFERENCES, Context.MODE_PRIVATE).edit();
editor.putString(MAPBOX_SHARED_PREFERENCE_RESOURCES_CACHE_PATH, path);
editor.apply();
setResourcesCachePath(context, path);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.mapbox.mapboxsdk;

import android.text.format.DateUtils;

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

public class AccountsManagerTest {
@Test
public void testIsExpired() {
long now = AccountsManager.getNow();

long defaultValue = 0L;
long tooOld = now - DateUtils.HOUR_IN_MILLIS - 1;
long futureValue = now + 1;
long immediatePast = now - 1;

Assert.assertTrue(AccountsManager.isExpired(now, defaultValue));
Assert.assertTrue(AccountsManager.isExpired(now, tooOld));

Assert.assertFalse(AccountsManager.isExpired(now, futureValue));
Assert.assertFalse(AccountsManager.isExpired(now, immediatePast));
}
}
2 changes: 2 additions & 0 deletions platform/android/gradle/dependencies.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ ext {
mapboxTelemetry : '4.4.1',
mapboxCore : '1.3.0',
mapboxGestures : '0.4.1',
mapboxAccounts : '0.1.0',
supportLib : '27.1.1',
constraintLayout: '1.1.2',
uiAutomator : '2.1.3',
Expand Down Expand Up @@ -39,6 +40,7 @@ ext {
mapboxJavaGeoJSON : "com.mapbox.mapboxsdk:mapbox-sdk-geojson:${versions.mapboxServices}",
mapboxAndroidTelemetry : "com.mapbox.mapboxsdk:mapbox-android-telemetry:${versions.mapboxTelemetry}",
mapboxAndroidGestures : "com.mapbox.mapboxsdk:mapbox-android-gestures:${versions.mapboxGestures}",
mapboxAndroidAccounts : "com.mapbox.mapboxsdk:mapbox-android-accounts:${versions.mapboxAccounts}",
mapboxJavaTurf : "com.mapbox.mapboxsdk:mapbox-sdk-turf:${versions.mapboxServices}",

junit : "junit:junit:${versions.junit}",
Expand Down

0 comments on commit d0a1526

Please sign in to comment.