From 8f829be03342250f7a41487edb49a71a3a92ebcf Mon Sep 17 00:00:00 2001 From: Arnaud Roland Date: Tue, 29 Oct 2024 16:49:35 +0100 Subject: [PATCH] release: SDK 2.1.0 --- Sources/buildSrc/src/main/java/Consts.kt | 8 +- .../gradle/wrapper/gradle-wrapper.properties | 4 +- .../android/BatchProfileAttributeEditor.java | 57 + .../android/BatchSMSSubscriptionState.java | 12 + .../android/WebserviceParameterUtils.java | 1 - .../SystemParameterHelper.java | 34 +- .../SystemParameterRegistry.java | 7 +- .../android/debug/BatchDebugActivity.java | 5 + .../messaging/view/formats/WebFormatView.java | 1 + .../batch/android/module/ProfileModule.java | 10 + .../android/profile/ProfileDataHelper.java | 46 +- .../profile/ProfileDataSerializer.java | 11 + .../profile/ProfileUpdateOperation.java | 47 + .../sdk/src/main/res/values-v35/values.xml | 6 + Sources/sdk/src/main/res/values/values.xml | 2 + .../BatchProfileAttributeEditorTest.kt | 7 + .../profile/ProfileDataHelperTest.java | 32 + .../profile/ProfileDataSerializerTest.kt | 22 + proguard-mappings/2.1.0/checksum.sha | 1 + proguard-mappings/2.1.0/mapping.txt | 11727 ++++++++++++++++ 20 files changed, 12027 insertions(+), 13 deletions(-) create mode 100644 Sources/sdk/src/main/java/com/batch/android/BatchSMSSubscriptionState.java create mode 100644 Sources/sdk/src/main/res/values-v35/values.xml create mode 100644 proguard-mappings/2.1.0/checksum.sha create mode 100644 proguard-mappings/2.1.0/mapping.txt diff --git a/Sources/buildSrc/src/main/java/Consts.kt b/Sources/buildSrc/src/main/java/Consts.kt index b1944f1..b689a46 100644 --- a/Sources/buildSrc/src/main/java/Consts.kt +++ b/Sources/buildSrc/src/main/java/Consts.kt @@ -1,18 +1,18 @@ object ProjectConsts { - const val COMPILE_SDK = 34 + const val COMPILE_SDK = 35 const val KOTLIN_VERSION = "1.9.0" const val KOTLIN_COROUTINES_VERSION = "1.7.1" const val ANDROID_LINT_VERSION = "30.1.2" - const val ANDROID_GRADLE_PLUGIN_VERSION = "8.3.0" + const val ANDROID_GRADLE_PLUGIN_VERSION = "8.6.0" const val GMS_GRADLE_PLUGIN_VERSION = "4.3.14" } object SDKConsts { - const val VERSION = "2.0.3" - const val API_LEVEL = 200 + const val VERSION = "2.1.0" + const val API_LEVEL = 210 const val MESSAGING_API_LEVEL = 12 const val MIN_SDK = 21 diff --git a/Sources/gradle/wrapper/gradle-wrapper.properties b/Sources/gradle/wrapper/gradle-wrapper.properties index 70ed048..9d855c8 100644 --- a/Sources/gradle/wrapper/gradle-wrapper.properties +++ b/Sources/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Tue Apr 16 15:13:35 CEST 2024 +#Mon Oct 07 16:54:16 CEST 2024 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/Sources/sdk/src/main/java/com/batch/android/BatchProfileAttributeEditor.java b/Sources/sdk/src/main/java/com/batch/android/BatchProfileAttributeEditor.java index 99bc51f..1a4af8d 100644 --- a/Sources/sdk/src/main/java/com/batch/android/BatchProfileAttributeEditor.java +++ b/Sources/sdk/src/main/java/com/batch/android/BatchProfileAttributeEditor.java @@ -137,6 +137,63 @@ public BatchProfileAttributeEditor setEmailMarketingSubscription(@NonNull BatchE return this; } + /** + * Set the profile phone number. + *

+ * Note: This method requires to already have a registered identifier for the user + * or to call {@link Batch.Profile#identify(String)} method before this one. + *

+ * Example: + *

+     * Batch.Profile.identify("my_custom_user_id")
+     * Batch.Profile.editor().setPhoneNumber("+33123456789").save()
+     * 
+ * @param phoneNumber A valid E.164 formatted string. Must start with a `+` and not be no longer + * than 15 digits without special characters (eg: "+33123456789"). Null to reset. + * @see E.164 + * @return This object instance, for method chaining. + */ + public BatchProfileAttributeEditor setPhoneNumber(@Nullable String phoneNumber) { + Context context = RuntimeManagerProvider.get().getContext(); + if (context == null) { + Logger.error(TAG, "Batch does not have a context yet. Make sure Batch is started beforehand."); + return this; + } + + // Ensure profile is logged in + String customUserID = UserModuleProvider.get().getCustomID(context); + if (customUserID == null) { + Logger.error( + TAG, + "You cannot set/reset a phone number to an anonymous profile. Please use the `Batch.Profile.identify` method beforehand." + ); + return this; + } + + // Ensure phone number is valid + if (ProfileDataHelper.isNotValidPhoneNumber(phoneNumber)) { + Logger.error( + TAG, + "setPhoneNumber called with invalid phone number format. Please make sure that the string starts with a `+` and is no longer than 15 digits." + ); + return this; + } + this.profileUpdateOperation.setPhoneNumber(phoneNumber); + return this; + } + + /** + * Set the profile SMS marketing subscription state. + *

+ * Note that profile's subscription status is automatically set to unsubscribed when they send a STOP message. + * @param state State of the subscription + * @return This object instance, for method chaining. + */ + public BatchProfileAttributeEditor setSMSMarketingSubscription(@NonNull BatchSMSSubscriptionState state) { + this.profileUpdateOperation.setSMSMarketing(state); + return this; + } + /** * Set a custom profile attribute for a key. * diff --git a/Sources/sdk/src/main/java/com/batch/android/BatchSMSSubscriptionState.java b/Sources/sdk/src/main/java/com/batch/android/BatchSMSSubscriptionState.java new file mode 100644 index 0000000..d6185df --- /dev/null +++ b/Sources/sdk/src/main/java/com/batch/android/BatchSMSSubscriptionState.java @@ -0,0 +1,12 @@ +package com.batch.android; + +import com.batch.android.annotation.PublicSDK; + +/** + * Enum defining the state of an SMS subscription + */ +@PublicSDK +public enum BatchSMSSubscriptionState { + SUBSCRIBED, + UNSUBSCRIBED, +} diff --git a/Sources/sdk/src/main/java/com/batch/android/WebserviceParameterUtils.java b/Sources/sdk/src/main/java/com/batch/android/WebserviceParameterUtils.java index c02beab..af20493 100644 --- a/Sources/sdk/src/main/java/com/batch/android/WebserviceParameterUtils.java +++ b/Sources/sdk/src/main/java/com/batch/android/WebserviceParameterUtils.java @@ -4,7 +4,6 @@ import androidx.annotation.NonNull; import com.batch.android.core.systemparameters.SystemParameter; import com.batch.android.core.systemparameters.SystemParameterRegistry; -import com.batch.android.core.systemparameters.SystemParameterShortName; import com.batch.android.di.providers.DataCollectionModuleProvider; import com.batch.android.di.providers.SystemParameterRegistryProvider; import com.batch.android.json.JSONObject; diff --git a/Sources/sdk/src/main/java/com/batch/android/core/systemparameters/SystemParameterHelper.java b/Sources/sdk/src/main/java/com/batch/android/core/systemparameters/SystemParameterHelper.java index 7dc52d8..d7fd20e 100644 --- a/Sources/sdk/src/main/java/com/batch/android/core/systemparameters/SystemParameterHelper.java +++ b/Sources/sdk/src/main/java/com/batch/android/core/systemparameters/SystemParameterHelper.java @@ -6,9 +6,11 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.os.Build; import androidx.annotation.NonNull; -import com.batch.android.core.Logger; +import androidx.annotation.Nullable; +import com.batch.android.core.ParameterKeys; import com.batch.android.core.Parameters; import com.batch.android.core.Webservice; +import com.batch.android.di.providers.ParametersProvider; import com.batch.android.json.JSONException; import com.batch.android.json.JSONObject; import java.util.Date; @@ -29,6 +31,7 @@ public final class SystemParameterHelper { * @param applicationContext The application context. * @return The application bundle name. */ + @NonNull public static String getBundleName(Context applicationContext) { return applicationContext.getPackageName(); } @@ -38,6 +41,7 @@ public static String getBundleName(Context applicationContext) { * * @return timezone or null on failure. */ + @Nullable public static String getDeviceTimezone() { try { return TimeZone.getDefault().getID(); @@ -51,6 +55,7 @@ public static String getDeviceTimezone() { * * @return language */ + @NonNull public static String getDeviceLanguage() { return Locale.getDefault().toLanguageTag(); } @@ -60,6 +65,7 @@ public static String getDeviceLanguage() { * * @return country */ + @NonNull public static String getDeviceCountry() { return Locale.getDefault().getCountry(); } @@ -69,6 +75,7 @@ public static String getDeviceCountry() { * * @return The current date */ + @NonNull public static String getDeviceDate() { return Webservice.formatDate(new Date()); } @@ -79,6 +86,7 @@ public static String getDeviceDate() { * @param applicationContext The application context. * @return Installation date or null on failure. */ + @Nullable public static Long getFirstInstallDate(Context applicationContext) { try { PackageManager packageManager = applicationContext.getPackageManager(); @@ -96,6 +104,7 @@ public static Long getFirstInstallDate(Context applicationContext) { * @param applicationContext The application context. * @return Last update date or null on failure. */ + @Nullable public static Long getLastUpdateDate(Context applicationContext) { try { PackageManager packageManager = applicationContext.getPackageManager(); @@ -107,11 +116,24 @@ public static Long getLastUpdateDate(Context applicationContext) { return null; } + /** + * Get the device install date. + * + * @param context Android's context to access shared preferences + * @return The device install date + */ + @Nullable + public static Long getDeviceInstallDate(Context context) { + String value = ParametersProvider.get(context).get(ParameterKeys.INSTALL_TIMESTAMP_KEY); + return value != null ? Long.parseLong(value) : null; + } + /** * Return the Brand name of the device * * @return Brand name if found, null otherwise */ + @Nullable public static String getDeviceBrand() { try { return Build.BRAND; @@ -125,6 +147,7 @@ public static String getDeviceBrand() { * * @return The device model if found, null otherwise. */ + @Nullable public static String getDeviceModel() { try { return Build.MODEL; @@ -139,6 +162,7 @@ public static String getDeviceModel() { * @param applicationContext The application context. * @return AppVersion if found, null otherwise */ + @Nullable public static String getAppVersion(Context applicationContext) { try { PackageInfo info = applicationContext @@ -156,6 +180,7 @@ public static String getAppVersion(Context applicationContext) { * @param applicationContext The application context. * @return AppVersion code if found, null otherwise */ + @Nullable public static Integer getAppVersionCode(Context applicationContext) { try { PackageManager packageManager = applicationContext.getApplicationContext().getPackageManager(); @@ -175,6 +200,7 @@ public static Integer getAppVersionCode(Context applicationContext) { * * @return Version. */ + @NonNull public static String getOSVersion() { return String.format("Android %s", Build.VERSION.RELEASE); } @@ -184,6 +210,7 @@ public static String getOSVersion() { * * @return Bridge version string */ + @NonNull public static String getBridgeVersion() { return System.getProperty(Parameters.BRIDGE_VERSION_ENVIRONEMENT_VAR, ""); } @@ -193,6 +220,7 @@ public static String getBridgeVersion() { * * @return Plugin version string */ + @NonNull public static String getPluginVersion() { return System.getProperty(Parameters.PLUGIN_VERSION_ENVIRONEMENT_VAR, ""); } @@ -201,6 +229,7 @@ public static String getPluginVersion() { * Get the android sdk api level * @return The android sdk api level */ + @NonNull public static String getOSSdkLevel() { return String.valueOf(Build.VERSION.SDK_INT); } @@ -209,6 +238,7 @@ public static String getOSSdkLevel() { * Get the batch sdk api level * @return The batch sdk api level */ + @NonNull public static String getSdkApiLevel() { return String.valueOf(Parameters.API_LEVEL); } @@ -217,6 +247,7 @@ public static String getSdkApiLevel() { * Get the batch sdk messaging api level * @return The batch sdk messaging api level */ + @NonNull public static String getSdkMessagingApiLevel() { return String.valueOf(Parameters.MESSAGING_API_LEVEL); } @@ -229,6 +260,7 @@ public static String getSdkMessagingApiLevel() { * @return A JSONObject related to the given list of parameters * @throws JSONException parsing exception */ + @NonNull public static JSONObject serializeSystemParameters(@NonNull List parameters) throws JSONException { JSONObject serializedParameters = new JSONObject(); diff --git a/Sources/sdk/src/main/java/com/batch/android/core/systemparameters/SystemParameterRegistry.java b/Sources/sdk/src/main/java/com/batch/android/core/systemparameters/SystemParameterRegistry.java index 94b8791..92fd0f0 100644 --- a/Sources/sdk/src/main/java/com/batch/android/core/systemparameters/SystemParameterRegistry.java +++ b/Sources/sdk/src/main/java/com/batch/android/core/systemparameters/SystemParameterRegistry.java @@ -4,10 +4,8 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.batch.android.Batch; -import com.batch.android.core.ParameterKeys; import com.batch.android.core.Webservice; import com.batch.android.di.providers.DataCollectionModuleProvider; -import com.batch.android.di.providers.ParametersProvider; import com.batch.android.di.providers.UserModuleProvider; import com.batch.android.processor.Module; import com.batch.android.processor.Provide; @@ -58,7 +56,10 @@ private SystemParameterRegistry(@NonNull Context context) { SystemParameter deviceInstallDate = new WatchedSystemParameter( context, SystemParameterShortName.DEVICE_INSTALL_DATE, - () -> ParametersProvider.get(context).get(ParameterKeys.INSTALL_TIMESTAMP_KEY) + () -> { + Long date = SystemParameterHelper.getDeviceInstallDate(context); + return date != null ? Webservice.formatDate(new Date(date)) : null; + } ); SystemParameter bundleName = new WatchedSystemParameter( diff --git a/Sources/sdk/src/main/java/com/batch/android/debug/BatchDebugActivity.java b/Sources/sdk/src/main/java/com/batch/android/debug/BatchDebugActivity.java index 78173a6..4c4b859 100644 --- a/Sources/sdk/src/main/java/com/batch/android/debug/BatchDebugActivity.java +++ b/Sources/sdk/src/main/java/com/batch/android/debug/BatchDebugActivity.java @@ -82,6 +82,11 @@ public void onCampaignMenuSelected(String campaignToken) { @Override protected void onCreate(Bundle savedInstanceState) { + // Workaround to opt-out the android 15 edge to edge enforcement. + // This is a temporary fix since this api will be soon deprecated by google. + // But using the view compat to handle inset force us to bump the minimal androidx core version. + getTheme().applyStyle(R.style.com_batchsdk_OptOutEdgeToEdgeEnforcement, false); + super.onCreate(savedInstanceState); setContentView(R.layout.com_batchsdk_debug_view); if (savedInstanceState == null) { diff --git a/Sources/sdk/src/main/java/com/batch/android/messaging/view/formats/WebFormatView.java b/Sources/sdk/src/main/java/com/batch/android/messaging/view/formats/WebFormatView.java index ae1e581..2cce93e 100644 --- a/Sources/sdk/src/main/java/com/batch/android/messaging/view/formats/WebFormatView.java +++ b/Sources/sdk/src/main/java/com/batch/android/messaging/view/formats/WebFormatView.java @@ -118,6 +118,7 @@ public WebFormatView( webSettings.setSupportZoom(false); webSettings.setDefaultTextEncodingName("utf-8"); webSettings.setSupportMultipleWindows(true); + webSettings.setAllowContentAccess(false); // Work around an issue where android could show "ERR_CACHE_MISS" // In a perfect world we would like to make use of the browser cache diff --git a/Sources/sdk/src/main/java/com/batch/android/module/ProfileModule.java b/Sources/sdk/src/main/java/com/batch/android/module/ProfileModule.java index b8ada0f..c177058 100644 --- a/Sources/sdk/src/main/java/com/batch/android/module/ProfileModule.java +++ b/Sources/sdk/src/main/java/com/batch/android/module/ProfileModule.java @@ -89,6 +89,16 @@ public void identify(@Nullable String identifier) { return; } + if (ProfileDataHelper.isBlocklistedCustomUserID(identifier)) { + Logger.error( + TAG, + "identify called with a blocklisted identifier: `" + + identifier + + "`, Please ensure you have correctly implemented the API." + ); + return; + } + Context context = RuntimeManagerProvider.get().getContext(); if (context == null) { Logger.error(TAG, "Batch does not have a context yet. Make sure Batch is started."); diff --git a/Sources/sdk/src/main/java/com/batch/android/profile/ProfileDataHelper.java b/Sources/sdk/src/main/java/com/batch/android/profile/ProfileDataHelper.java index 2389ebf..69f589c 100644 --- a/Sources/sdk/src/main/java/com/batch/android/profile/ProfileDataHelper.java +++ b/Sources/sdk/src/main/java/com/batch/android/profile/ProfileDataHelper.java @@ -5,6 +5,7 @@ import androidx.annotation.Nullable; import com.batch.android.core.Logger; import java.net.URI; +import java.util.Arrays; import java.util.List; import java.util.Locale; import java.util.regex.Pattern; @@ -26,6 +27,11 @@ public class ProfileDataHelper { */ private static final Pattern EMAIL_KEY_PATTERN = Pattern.compile("^[^@\\r\\n\\t]+@[A-z0-9\\-\\.]+\\.[A-z0-9]+$"); + /** + * Valid phone number pattern + */ + private static final Pattern PHONE_NUMBER_KEY_PATTERN = Pattern.compile("^\\+[0-9]{1,15}$"); + /** * Attribute key pattern */ @@ -45,6 +51,22 @@ public class ProfileDataHelper { */ public static final int ATTR_URL_MAX_LENGTH = 2048; + /** + * List of blocklisted custom user identifiers. + */ + private static final List BLOCKLISTED_CUSTOM_USER_IDS = Arrays.asList( + "undefined", + "null", + "nil", + "(null)", + "[object object]", + "true", + "false", + "nan", + "infinity", + "-infinity" + ); + /** * Whether the identifier is NOT a valid custom user identifier * @@ -57,15 +79,35 @@ public static boolean isNotValidCustomUserID(@Nullable String identifier) { } /** - * Whether given email is valid + * Whether the identifier is blocklisted to avoid unintentional values from plugin conversion. + * + * @param identifier The custom user identifier. + * @return True if blocklisted, false otherwise + */ + public static boolean isBlocklistedCustomUserID(@Nullable String identifier) { + return identifier != null && BLOCKLISTED_CUSTOM_USER_IDS.contains(identifier.toLowerCase(Locale.US)); + } + + /** + * Whether the given email is NOT valid * * @param email the profile's email - * @return true if valid, false otherwise + * @return true if NOT valid, false otherwise */ public static boolean isNotValidEmail(String email) { return email != null && (!EMAIL_KEY_PATTERN.matcher(email).matches() || email.length() > EMAIL_MAX_LENGTH); } + /** + * Whether the given phone number is NOT valid + * + * @param phoneNumber the profile's phone number + * @return true if NOT valid, false otherwise + */ + public static boolean isNotValidPhoneNumber(String phoneNumber) { + return phoneNumber != null && (!PHONE_NUMBER_KEY_PATTERN.matcher(phoneNumber).matches()); + } + /** * Whether the given language is NOT valid. * diff --git a/Sources/sdk/src/main/java/com/batch/android/profile/ProfileDataSerializer.java b/Sources/sdk/src/main/java/com/batch/android/profile/ProfileDataSerializer.java index c55e263..6a9d21e 100644 --- a/Sources/sdk/src/main/java/com/batch/android/profile/ProfileDataSerializer.java +++ b/Sources/sdk/src/main/java/com/batch/android/profile/ProfileDataSerializer.java @@ -13,6 +13,8 @@ public class ProfileDataSerializer { private static final String EMAIL_KEY = "email"; private static final String EMAIL_MARKETING = "email_marketing"; + private static final String PHONE_NUMBER_KEY = "phone_number"; + private static final String SMS_MARKETING = "sms_marketing"; private static final String LANGUAGE_KEY = "language"; private static final String REGION_KEY = "region"; private static final String CUSTOM_ATTRIBUTES_KEY = "custom_attributes"; @@ -33,6 +35,11 @@ public static JSONObject serialize(@NonNull ProfileUpdateOperation profileUpdate serializedProfile.put(EMAIL_KEY, email.getSerializedValue()); } + ProfileDeletableAttribute phoneNumber = profileUpdateOperation.getPhoneNumber(); + if (phoneNumber != null) { + serializedProfile.put(PHONE_NUMBER_KEY, phoneNumber.getSerializedValue()); + } + ProfileDeletableAttribute language = profileUpdateOperation.getLanguage(); if (language != null) { serializedProfile.put(LANGUAGE_KEY, language.getSerializedValue()); @@ -47,6 +54,10 @@ public static JSONObject serialize(@NonNull ProfileUpdateOperation profileUpdate serializedProfile.put(EMAIL_MARKETING, profileUpdateOperation.getEmailMarketing().name().toLowerCase()); } + if (profileUpdateOperation.getSMSMarketing() != null) { + serializedProfile.put(SMS_MARKETING, profileUpdateOperation.getSMSMarketing().name().toLowerCase()); + } + Map customAttributes = profileUpdateOperation.getCustomAttributes(); if (!customAttributes.isEmpty()) { JSONObject serializedCustomAttributes = new JSONObject(); diff --git a/Sources/sdk/src/main/java/com/batch/android/profile/ProfileUpdateOperation.java b/Sources/sdk/src/main/java/com/batch/android/profile/ProfileUpdateOperation.java index 0b0111b..a7a7c25 100644 --- a/Sources/sdk/src/main/java/com/batch/android/profile/ProfileUpdateOperation.java +++ b/Sources/sdk/src/main/java/com/batch/android/profile/ProfileUpdateOperation.java @@ -3,6 +3,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.batch.android.BatchEmailSubscriptionState; +import com.batch.android.BatchSMSSubscriptionState; import com.batch.android.user.AttributeType; import com.batch.android.user.UserAttribute; import java.util.ArrayList; @@ -27,6 +28,18 @@ public class ProfileUpdateOperation { @Nullable private BatchEmailSubscriptionState emailMarketing; + /** + * Profile related phone number + */ + @Nullable + private ProfileDeletableAttribute phoneNumber; + + /** + * Profile related SMS marketing subscription state + */ + @Nullable + private BatchSMSSubscriptionState smsMarketing; + /** * Profile related language */ @@ -79,6 +92,40 @@ public void setEmailMarketing(@NonNull BatchEmailSubscriptionState emailMarketin this.emailMarketing = emailMarketing; } + /** + * Get the phone number + * @return The phone number + */ + @Nullable + public ProfileDeletableAttribute getPhoneNumber() { + return phoneNumber; + } + + /** + * Set a phone number + * @param phoneNumber The phone number + */ + public void setPhoneNumber(@Nullable String phoneNumber) { + this.phoneNumber = new ProfileDeletableAttribute(phoneNumber); + } + + /** + * Get the SMS marketing subscription state + * @return The SMS marketing subscription state + */ + @Nullable + public BatchSMSSubscriptionState getSMSMarketing() { + return smsMarketing; + } + + /** + * Set an SMS marketing subscription state + * @param smsMarketing The SMS marketing subscription state + */ + public void setSMSMarketing(@NonNull BatchSMSSubscriptionState smsMarketing) { + this.smsMarketing = smsMarketing; + } + /** * Get the profile language * @return The profile language diff --git a/Sources/sdk/src/main/res/values-v35/values.xml b/Sources/sdk/src/main/res/values-v35/values.xml new file mode 100644 index 0000000..cb4ccda --- /dev/null +++ b/Sources/sdk/src/main/res/values-v35/values.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/Sources/sdk/src/main/res/values/values.xml b/Sources/sdk/src/main/res/values/values.xml index 0a3bb58..7ac717a 100644 --- a/Sources/sdk/src/main/res/values/values.xml +++ b/Sources/sdk/src/main/res/values/values.xml @@ -8,4 +8,6 @@