From 0181ef8f63351aa2724d5a89ba9ea3e5484e3aaf Mon Sep 17 00:00:00 2001 From: Pablo Guardiola Date: Thu, 30 May 2019 11:24:24 -0400 Subject: [android] add support for external sdk clients to be able to manage the tokens on their side (#14631) --- .../java/com/mapbox/mapboxsdk/AccountsManager.java | 96 +++++++++++++++++----- .../mapboxsdk/constants/MapboxConstants.java | 6 ++ .../com/mapbox/mapboxsdk/AccountsManagerTest.java | 45 ++++++++-- platform/android/gradle/dependencies.gradle | 2 +- 4 files changed, 124 insertions(+), 25 deletions(-) (limited to 'platform/android') diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/AccountsManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/AccountsManager.java index 4fd0200a37..5b8f10e01d 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/AccountsManager.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/AccountsManager.java @@ -2,41 +2,94 @@ package com.mapbox.mapboxsdk; import android.content.Context; import android.content.SharedPreferences; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.support.annotation.NonNull; +import android.support.annotation.VisibleForTesting; import android.text.TextUtils; import android.text.format.DateUtils; import com.mapbox.android.accounts.v1.MapboxAccounts; import com.mapbox.mapboxsdk.constants.MapboxConstants; +import com.mapbox.mapboxsdk.log.Logger; + +import static com.mapbox.mapboxsdk.constants.MapboxConstants.KEY_PREFERENCE_SKU_TOKEN; /** * 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 TAG = "Mbgl-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 SharedPreferences sharedPreferences; private String skuToken; + private long timestamp; + private boolean isManaged; AccountsManager() { - String userId = validateUserId(); - validateRotation(userId); + isManaged = isSkuTokenManaged(); + initialize(); + } + + @VisibleForTesting + AccountsManager(SharedPreferences sharedPreferences, boolean isManaged) { + this.sharedPreferences = sharedPreferences; + this.isManaged = isManaged; + initialize(); + } + + private void initialize() { + retrieveSkuTokenAndTimestamp(); + if (isManaged) { + String userId = validateUserId(); + validateRotation(userId); + } + } + + private boolean isSkuTokenManaged() { + boolean value = MapboxConstants.DEFAULT_MANAGE_SKU_TOKEN; + try { + // Try getting a custom value from the app Manifest + ApplicationInfo appInfo = retrieveApplicationInfo(); + if (appInfo.metaData != null) { + value = appInfo.metaData.getBoolean( + MapboxConstants.KEY_META_DATA_MANAGE_SKU_TOKEN, + MapboxConstants.DEFAULT_MANAGE_SKU_TOKEN + ); + } + } catch (Exception exception) { + Logger.e(TAG, "Failed to read the package metadata: ", exception); + } + + return value; + } + + private ApplicationInfo retrieveApplicationInfo() throws PackageManager.NameNotFoundException { + return Mapbox.getApplicationContext().getPackageManager().getApplicationInfo( + Mapbox.getApplicationContext().getPackageName(), + PackageManager.GET_META_DATA); + } + + private void retrieveSkuTokenAndTimestamp() { + SharedPreferences sharedPreferences = getSharedPreferences(); + skuToken = sharedPreferences.getString(KEY_PREFERENCE_SKU_TOKEN, ""); + timestamp = sharedPreferences.getLong(PREFERENCE_TIMESTAMP, 0L); } private String validateUserId() { @@ -53,23 +106,25 @@ class AccountsManager { } 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)) { + if (TextUtils.isEmpty(skuToken) || timestamp == 0L) { skuToken = generateSkuToken(userId); timestamp = persistRotation(skuToken); } } String getSkuToken() { - if (isExpired()) { + if (isManaged) { + if (isExpired()) { + SharedPreferences sharedPreferences = getSharedPreferences(); + String userId = sharedPreferences.getString(PREFERENCE_USER_ID, ""); + skuToken = generateSkuToken(userId); + timestamp = persistRotation(skuToken); + } + } else { SharedPreferences sharedPreferences = getSharedPreferences(); - String userId = sharedPreferences.getString(PREFERENCE_USER_ID, ""); - skuToken = generateSkuToken(userId); - timestamp = persistRotation(skuToken); + String notManagedSkuToken = sharedPreferences.getString(KEY_PREFERENCE_SKU_TOKEN, ""); + skuToken = notManagedSkuToken; } - return skuToken; } @@ -85,15 +140,18 @@ class AccountsManager { long now = getNow(); SharedPreferences.Editor editor = getSharedPreferences().edit(); editor.putLong(PREFERENCE_TIMESTAMP, now); - editor.putString(PREFERENCE_SKU_TOKEN, skuToken); + editor.putString(KEY_PREFERENCE_SKU_TOKEN, skuToken); editor.apply(); return now; } @NonNull private SharedPreferences getSharedPreferences() { - return Mapbox.getApplicationContext() + if (sharedPreferences == null) { + sharedPreferences = Mapbox.getApplicationContext() .getSharedPreferences(MapboxConstants.MAPBOX_SHARED_PREFERENCES, Context.MODE_PRIVATE); + } + return sharedPreferences; } static long getNow() { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java index 30ff649032..2c906e7203 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java @@ -37,6 +37,12 @@ public class MapboxConstants { */ public static final boolean DEFAULT_MEASURE_TILE_DOWNLOAD_ON = false; + public static final String KEY_PREFERENCE_SKU_TOKEN = "com.mapbox.mapboxsdk.accounts.skutoken"; + + public static final String KEY_META_DATA_MANAGE_SKU_TOKEN = "com.mapbox.ManageSkuToken"; + + public static final boolean DEFAULT_MANAGE_SKU_TOKEN = true; + /** * Unmeasured state */ diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/AccountsManagerTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/AccountsManagerTest.java index 3f846e6640..5ce71ceacf 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/AccountsManagerTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/AccountsManagerTest.java @@ -1,10 +1,18 @@ package com.mapbox.mapboxsdk; +import android.content.SharedPreferences; import android.text.format.DateUtils; -import org.junit.Assert; import org.junit.Test; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.KEY_PREFERENCE_SKU_TOKEN; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.RETURNS_DEEP_STUBS; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + public class AccountsManagerTest { @Test public void testIsExpired() { @@ -15,10 +23,37 @@ public class AccountsManagerTest { long futureValue = now + 1; long immediatePast = now - 1; - Assert.assertTrue(AccountsManager.isExpired(now, defaultValue)); - Assert.assertTrue(AccountsManager.isExpired(now, tooOld)); + assertTrue(AccountsManager.isExpired(now, defaultValue)); + assertTrue(AccountsManager.isExpired(now, tooOld)); + + assertFalse(AccountsManager.isExpired(now, futureValue)); + assertFalse(AccountsManager.isExpired(now, immediatePast)); + } + + @Test + public void checksSkuTokenExternalManagement() { + SharedPreferences mockedSharedPreferences = mock(SharedPreferences.class); + when(mockedSharedPreferences.getString(KEY_PREFERENCE_SKU_TOKEN, "")).thenReturn("external-sku-token"); + boolean isNotManaged = false; + AccountsManager theAccountsManager = new AccountsManager(mockedSharedPreferences, isNotManaged); + + String skuToken = theAccountsManager.getSkuToken(); + + assertEquals("external-sku-token", skuToken); + } + + @Test + public void checksSkuTokenInternalManagement() { + SharedPreferences mockedSharedPreferences = mock(SharedPreferences.class, RETURNS_DEEP_STUBS); + when(mockedSharedPreferences.getString("com.mapbox.mapboxsdk.accounts.userid", "")) + .thenReturn("any-user-id"); + boolean isManaged = true; + AccountsManager theAccountsManager = new AccountsManager(mockedSharedPreferences, isManaged); + + String skuToken = theAccountsManager.getSkuToken(); - Assert.assertFalse(AccountsManager.isExpired(now, futureValue)); - Assert.assertFalse(AccountsManager.isExpired(now, immediatePast)); + assertFalse(skuToken.isEmpty()); + assertTrue(skuToken.startsWith("100")); + assertTrue(skuToken.endsWith("any-user-id")); } } diff --git a/platform/android/gradle/dependencies.gradle b/platform/android/gradle/dependencies.gradle index d681853a6b..a6b205309b 100644 --- a/platform/android/gradle/dependencies.gradle +++ b/platform/android/gradle/dependencies.gradle @@ -11,7 +11,7 @@ ext { mapboxTelemetry : '4.4.1', mapboxCore : '1.3.0', mapboxGestures : '0.4.2', - mapboxAccounts : '0.1.0', + mapboxAccounts : '0.2.0', supportLib : '27.1.1', constraintLayout: '1.1.2', uiAutomator : '2.1.3', -- cgit v1.2.1