diff --git a/CHANGELOG.md b/CHANGELOG.md
index f92627973..989625a8f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+# 2019-06-17 - v5.4.3
+
+#### Improvements
+
+* Made Android ID collection optional on pre-Oreo targets.
+* Fixed "Who" card in the Message Center.
+
# 2019-05-14 - v5.4.2
#### Fixes
diff --git a/README.md b/README.md
index 88012795a..7f2987e64 100644
--- a/README.md
+++ b/README.md
@@ -13,7 +13,7 @@ use your app, to talk to them at the right time, and in the right way.
##### [Release Notes](https://learn.apptentive.com/knowledge-base/android-sdk-release-notes/)
-##### Binary releases are hosted for Maven [here](http://search.maven.org/#artifactdetails|com.apptentive|apptentive-android|5.4.2|aar)
+##### Binary releases are hosted for Maven [here](http://search.maven.org/#artifactdetails|com.apptentive|apptentive-android|5.4.3|aar)
#### Reporting Bugs
diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/ApptentiveConfiguration.java b/apptentive/src/main/java/com/apptentive/android/sdk/ApptentiveConfiguration.java
index 7e32f832f..f8a52d078 100644
--- a/apptentive/src/main/java/com/apptentive/android/sdk/ApptentiveConfiguration.java
+++ b/apptentive/src/main/java/com/apptentive/android/sdk/ApptentiveConfiguration.java
@@ -20,6 +20,7 @@ public class ApptentiveConfiguration {
private boolean shouldSanitizeLogMessages;
private boolean troubleshootingModeEnabled;
private Encryption encryption;
+ private boolean shouldCollectAndroidIdOnPreOreoTargets;
public ApptentiveConfiguration(@NonNull String apptentiveKey, @NonNull String apptentiveSignature) {
if (StringUtils.isNullOrEmpty(apptentiveKey)) {
@@ -36,6 +37,7 @@ public ApptentiveConfiguration(@NonNull String apptentiveKey, @NonNull String ap
this.shouldEncryptStorage = false;
this.shouldSanitizeLogMessages = true;
this.troubleshootingModeEnabled = true;
+ this.shouldCollectAndroidIdOnPreOreoTargets = true;
}
public String getApptentiveKey() {
@@ -122,4 +124,19 @@ public ApptentiveConfiguration setTroubleshootingModeEnabled(boolean troubleshoo
this.troubleshootingModeEnabled = troubleshootingModeEnabled;
return this;
}
+
+ /**
+ * Overrides if the SDK should collect Android ID on pre Android-O targets. If set to false
+ * a random value would be generated on the initial SDK launch and provided on each subsequent launch.
+ */
+ public void setShouldCollectAndroidIdOnPreOreoTargets(boolean shouldCollectAndroidIdOnPreOreoTargets) {
+ this.shouldCollectAndroidIdOnPreOreoTargets = shouldCollectAndroidIdOnPreOreoTargets;
+ }
+
+ /**
+ * Indicates if the SDK should collect Android ID on pre Android-O targets.
+ */
+ public boolean shouldCollectAndroidIdOnPreOreoTargets() {
+ return shouldCollectAndroidIdOnPreOreoTargets;
+ }
}
diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/ApptentiveInternal.java b/apptentive/src/main/java/com/apptentive/android/sdk/ApptentiveInternal.java
index aab7edc45..f5a5bff7c 100644
--- a/apptentive/src/main/java/com/apptentive/android/sdk/ApptentiveInternal.java
+++ b/apptentive/src/main/java/com/apptentive/android/sdk/ApptentiveInternal.java
@@ -42,7 +42,6 @@
import com.apptentive.android.sdk.module.engagement.interaction.InteractionManager;
import com.apptentive.android.sdk.module.engagement.interaction.model.MessageCenterInteraction;
import com.apptentive.android.sdk.module.messagecenter.MessageManager;
-import com.apptentive.android.sdk.module.metric.MetricModule;
import com.apptentive.android.sdk.module.rating.IRatingProvider;
import com.apptentive.android.sdk.module.rating.impl.GooglePlayRatingProvider;
import com.apptentive.android.sdk.module.survey.OnSurveyFinishedListener;
@@ -153,7 +152,7 @@ public ApptentiveInternal(Context appContext) {
appRelease = null;
}
- private ApptentiveInternal(Application application, ApptentiveConfiguration configuration) {
+ private ApptentiveInternal(Application application, ApptentiveConfiguration configuration, @NonNull String androidID) {
if (configuration == null) {
throw new IllegalArgumentException("Configuration is null");
}
@@ -174,7 +173,8 @@ private ApptentiveInternal(Application application, ApptentiveConfiguration conf
globalSharedPrefs = application.getSharedPreferences(Constants.PREF_NAME, Context.MODE_PRIVATE);
apptentiveHttpClient = new ApptentiveHttpClient(apptentiveKey, apptentiveSignature, getEndpointBase(globalSharedPrefs));
- conversationManager = new ConversationManager(appContext, Util.getInternalDir(appContext, CONVERSATIONS_DIR, true), encryption);
+ DeviceManager deviceManager = new DeviceManager(androidID);
+ conversationManager = new ConversationManager(appContext, Util.getInternalDir(appContext, CONVERSATIONS_DIR, true), encryption, deviceManager);
appRelease = AppReleaseManager.generateCurrentAppRelease(application, this);
taskManager = new ApptentiveTaskManager(appContext, apptentiveHttpClient, encryption);
@@ -232,17 +232,20 @@ static void createInstance(@NonNull Application application, @NonNull Apptentive
synchronized (ApptentiveInternal.class) {
if (sApptentiveInternal == null) {
- ApptentiveLog.i("Registering Apptentive Android SDK %s", Constants.getApptentiveSdkVersion());
- ApptentiveLog.v("ApptentiveKey=%s ApptentiveSignature=%s", apptentiveKey, apptentiveSignature);
- sApptentiveInternal = new ApptentiveInternal(application, configuration);
- dispatchOnConversationQueue(new DispatchTask() {
- @Override
- protected void execute() {
- sApptentiveInternal.start();
- }
- });
+ ApptentiveLog.i("Registering Apptentive Android SDK %s", Constants.getApptentiveSdkVersion());
+ ApptentiveLog.v("ApptentiveKey=%s ApptentiveSignature=%s", apptentiveKey, apptentiveSignature);
+ // resolve Android ID
+ boolean shouldGenerateRandomAndroidID = Build.VERSION.SDK_INT < Build.VERSION_CODES.O && !configuration.shouldCollectAndroidIdOnPreOreoTargets();
+ String androidID = resolveAndroidID(application.getApplicationContext(), shouldGenerateRandomAndroidID);
+ sApptentiveInternal = new ApptentiveInternal(application, configuration, androidID);
+ dispatchOnConversationQueue(new DispatchTask() {
+ @Override
+ protected void execute() {
+ sApptentiveInternal.start();
+ }
+ });
- ApptentiveActivityLifecycleCallbacks.register(application);
+ ApptentiveActivityLifecycleCallbacks.register(application);
} else {
ApptentiveLog.w("Apptentive instance is already initialized");
}
@@ -1191,4 +1194,36 @@ private static void logException(Exception e) {
}
//endregion
+
+ //region Android ID
+
+ private static final String PREFS_NAME_ANDROID_ID = "com.apptentive.sdk.androidID";
+ private static final String PREFS_KEY_NAME_ANDROID_ID = "androidID";
+
+ private static String resolveAndroidID(Context context, boolean shouldGenerateRandomAndroidID) {
+ if (shouldGenerateRandomAndroidID) {
+ String existingAndroidID = loadAndroidID(context);
+ if (existingAndroidID != null) {
+ return existingAndroidID;
+ }
+
+ String androidID = StringUtils.randomAndroidID();
+ saveAndroidID(context, androidID);
+ return androidID;
+ }
+
+ return Util.getAndroidID(context);
+ }
+
+ private static String loadAndroidID(Context context) {
+ SharedPreferences sharedPreferences = context.getSharedPreferences(PREFS_NAME_ANDROID_ID, Context.MODE_PRIVATE);
+ return sharedPreferences.getString(PREFS_KEY_NAME_ANDROID_ID, null);
+ }
+
+ private static void saveAndroidID(Context context, String androidID) {
+ SharedPreferences sharedPreferences = context.getSharedPreferences(PREFS_NAME_ANDROID_ID, Context.MODE_PRIVATE);
+ sharedPreferences.edit().putString(PREFS_KEY_NAME_ANDROID_ID, androidID).apply();
+ }
+
+ //endregion
}
diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/comm/ApptentiveHttpClient.java b/apptentive/src/main/java/com/apptentive/android/sdk/comm/ApptentiveHttpClient.java
index 38c7678b4..37851e640 100644
--- a/apptentive/src/main/java/com/apptentive/android/sdk/comm/ApptentiveHttpClient.java
+++ b/apptentive/src/main/java/com/apptentive/android/sdk/comm/ApptentiveHttpClient.java
@@ -16,7 +16,7 @@
import com.apptentive.android.sdk.storage.AppRelease;
import com.apptentive.android.sdk.storage.AppReleaseManager;
import com.apptentive.android.sdk.storage.Device;
-import com.apptentive.android.sdk.storage.DeviceManager;
+import com.apptentive.android.sdk.storage.DevicePayloadDiff;
import com.apptentive.android.sdk.storage.PayloadRequestSender;
import com.apptentive.android.sdk.storage.Sdk;
import com.apptentive.android.sdk.storage.SdkManager;
@@ -168,7 +168,7 @@ public HttpJsonRequest createFirstLoginRequest(String token, AppRelease appRelea
ConversationTokenRequest conversationTokenRequest = new ConversationTokenRequest();
conversationTokenRequest.setSdkAndAppRelease(SdkManager.getPayload(sdk), AppReleaseManager.getPayload(appRelease));
- conversationTokenRequest.setDevice(DeviceManager.getDiffPayload(null, device));
+ conversationTokenRequest.setDevice(DevicePayloadDiff.getDiffPayload(null, device));
try {
conversationTokenRequest.put("token", token);
diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/conversation/Conversation.java b/apptentive/src/main/java/com/apptentive/android/sdk/conversation/Conversation.java
index e8e73762a..6995ff823 100644
--- a/apptentive/src/main/java/com/apptentive/android/sdk/conversation/Conversation.java
+++ b/apptentive/src/main/java/com/apptentive/android/sdk/conversation/Conversation.java
@@ -33,7 +33,7 @@
import com.apptentive.android.sdk.storage.DataChangedListener;
import com.apptentive.android.sdk.storage.Device;
import com.apptentive.android.sdk.storage.DeviceDataChangedListener;
-import com.apptentive.android.sdk.storage.DeviceManager;
+import com.apptentive.android.sdk.storage.DevicePayloadDiff;
import com.apptentive.android.sdk.storage.EncryptedFileSerializer;
import com.apptentive.android.sdk.storage.EventData;
import com.apptentive.android.sdk.storage.FileSerializer;
@@ -507,7 +507,7 @@ protected void execute() {
Device lastSentDevice = getLastSentDevice();
Device currentDevice = getDevice();
assertNotNull(currentDevice, "Current device object is null");
- DevicePayload devicePayload = DeviceManager.getDiffPayload(lastSentDevice, currentDevice);
+ DevicePayload devicePayload = DevicePayloadDiff.getDiffPayload(lastSentDevice, currentDevice);
if (devicePayload != null) {
addPayload(devicePayload);
setLastSentDevice(currentDevice != null ? currentDevice.clone() : null);
diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/conversation/ConversationManager.java b/apptentive/src/main/java/com/apptentive/android/sdk/conversation/ConversationManager.java
index 514d79b7d..ab233d99c 100644
--- a/apptentive/src/main/java/com/apptentive/android/sdk/conversation/ConversationManager.java
+++ b/apptentive/src/main/java/com/apptentive/android/sdk/conversation/ConversationManager.java
@@ -33,6 +33,7 @@
import com.apptentive.android.sdk.storage.AppReleaseManager;
import com.apptentive.android.sdk.storage.Device;
import com.apptentive.android.sdk.storage.DeviceManager;
+import com.apptentive.android.sdk.storage.DevicePayloadDiff;
import com.apptentive.android.sdk.storage.Sdk;
import com.apptentive.android.sdk.storage.SdkManager;
import com.apptentive.android.sdk.storage.SerializerException;
@@ -89,6 +90,11 @@ public class ConversationManager {
*/
private final Encryption encryption;
+ /**
+ * Responsible for generating device payloads.
+ */
+ private final DeviceManager deviceManager;
+
/**
* Current state of conversation metadata.
*/
@@ -103,7 +109,7 @@ public class ConversationManager {
*/
private boolean activeConversationFailedToResolve; // TODO: this is a temporary solution until we restore conversation state
- public ConversationManager(@NonNull Context context, @NonNull File conversationsStorageDir, @NonNull Encryption encryption) {
+ public ConversationManager(@NonNull Context context, @NonNull File conversationsStorageDir, @NonNull Encryption encryption, @NonNull DeviceManager deviceManager) {
if (context == null) {
throw new IllegalArgumentException("Context is null");
}
@@ -116,9 +122,14 @@ public ConversationManager(@NonNull Context context, @NonNull File conversations
throw new IllegalArgumentException("Encryption is null");
}
+ if (deviceManager == null) {
+ throw new IllegalArgumentException("Device manager is null");
+ }
+
this.contextRef = new WeakReference<>(context.getApplicationContext());
this.conversationsStorageDir = conversationsStorageDir;
this.encryption = encryption;
+ this.deviceManager = deviceManager;
ApptentiveNotificationCenter.defaultCenter()
.addObserver(NOTIFICATION_APP_ENTERED_FOREGROUND, new ApptentiveNotificationObserver() {
@@ -464,11 +475,11 @@ private HttpRequest fetchConversationToken(final Conversation conversation) {
ConversationTokenRequest conversationTokenRequest = new ConversationTokenRequest();
// Send the Device and Sdk now, so they are available on the server from the start.
- final Device device = DeviceManager.generateNewDevice(context);
+ final Device device = deviceManager.generateNewDevice(context);
final Sdk sdk = SdkManager.generateCurrentSdk(context);
final AppRelease appRelease = ApptentiveInternal.getInstance().getAppRelease();
- conversationTokenRequest.setDevice(DeviceManager.getDiffPayload(null, device));
+ conversationTokenRequest.setDevice(DevicePayloadDiff.getDiffPayload(null, device));
conversationTokenRequest.setSdkAndAppRelease(SdkManager.getPayload(sdk), AppReleaseManager.getPayload(appRelease));
HttpRequest request = getHttpClient()
@@ -957,7 +968,7 @@ public boolean accept(ConversationMetadataItem item) {
setActiveConversation(new Conversation(dataFile, messagesFile, conversationEncryption, payloadEncryptionKey));
// TODO: if we don't set these here - device payload would return 4xx error code
- activeConversation.setDevice(DeviceManager.generateNewDevice(getContext()));
+ activeConversation.setDevice(deviceManager.generateNewDevice(getContext()));
activeConversation.setAppRelease(ApptentiveInternal.getInstance().getAppRelease());
activeConversation.setSdk(SdkManager.generateCurrentSdk(getContext()));
}
@@ -998,7 +1009,7 @@ private void sendFirstLoginRequest(final String userId, final String token, fina
final AppRelease appRelease = ApptentiveInternal.getInstance().getAppRelease();
final Sdk sdk = SdkManager.generateCurrentSdk(getContext());
- final Device device = DeviceManager.generateNewDevice(getContext());
+ final Device device = deviceManager.generateNewDevice(getContext());
HttpJsonRequest request = getHttpClient().createFirstLoginRequest(token, appRelease, sdk, device, new HttpRequest.Listener() {
@Override
diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java
index 5e6912b99..debd7d76c 100644
--- a/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java
+++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/engagement/interaction/fragment/MessageCenterFragment.java
@@ -1034,7 +1034,7 @@ public void onCloseWhoCard(String buttonLabel) {
}
private boolean shouldOpenComposerAfterClosingWhoCard() {
- return interaction.getWhoCard().isRequire() && (recyclerViewContainsItemOfType(MESSAGE_CONTEXT) || recyclerViewContainsItemOfType(MESSAGE_OUTGOING));
+ return interaction.getWhoCard().isRequire() && !recyclerViewContainsItemOfType(MESSAGE_OUTGOING);
}
public void cleanupWhoCard() {
diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/WhoCard.java b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/WhoCard.java
index 6fe5aee85..77721ed39 100644
--- a/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/WhoCard.java
+++ b/apptentive/src/main/java/com/apptentive/android/sdk/module/messagecenter/model/WhoCard.java
@@ -70,10 +70,6 @@ public String getTitle() {
}
public String getNameHint() {
- if (isRequire() && isInitial()) {
- // The Who Card will show up right when MC is opened in this scenario. Don't ask for the name at this time.
- return null;
- }
return getApplicableConfig().optString(KEY_NAME_HINT, null);
}
diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/storage/DeviceManager.java b/apptentive/src/main/java/com/apptentive/android/sdk/storage/DeviceManager.java
index 538a87e05..5e977d3b7 100644
--- a/apptentive/src/main/java/com/apptentive/android/sdk/storage/DeviceManager.java
+++ b/apptentive/src/main/java/com/apptentive/android/sdk/storage/DeviceManager.java
@@ -12,21 +12,26 @@
import com.apptentive.android.sdk.ApptentiveLog;
import com.apptentive.android.sdk.model.Configuration;
-import com.apptentive.android.sdk.model.DevicePayload;
import com.apptentive.android.sdk.util.AdvertiserManager;
import com.apptentive.android.sdk.util.Constants;
-import com.apptentive.android.sdk.util.Util;
+import com.apptentive.android.sdk.util.StringUtils;
import java.util.Locale;
import java.util.TimeZone;
import static com.apptentive.android.sdk.debug.ErrorMetrics.logException;
-/**
- * A helper class with static methods for and diffing information about the current device.
- */
public class DeviceManager {
- public static Device generateNewDevice(Context context) {
+ private final String androidID;
+
+ public DeviceManager(String androidID) {
+ if (StringUtils.isNullOrEmpty(androidID)) {
+ throw new IllegalArgumentException("Android ID is null or empty");
+ }
+ this.androidID = androidID;
+ }
+
+ public Device generateNewDevice(Context context) {
Device device = new Device();
// First, get all the information we can load from static resources.
@@ -41,7 +46,7 @@ public static Device generateNewDevice(Context context) {
device.setBrand(Build.BRAND);
device.setCpu(Build.CPU_ABI);
device.setDevice(Build.DEVICE);
- device.setUuid(Util.getAndroidId(context));
+ device.setUuid(androidID);
device.setBuildType(Build.TYPE);
device.setBuildId(Build.ID);
@@ -82,150 +87,5 @@ public static Device generateNewDevice(Context context) {
device.setUtcOffset(String.valueOf((TimeZone.getDefault().getRawOffset() / 1000)));
return device;
}
-
- public static DevicePayload getDiffPayload(com.apptentive.android.sdk.storage.Device oldDevice, com.apptentive.android.sdk.storage.Device newDevice) {
- if (newDevice == null) {
- return null;
- }
-
- DevicePayload ret = new DevicePayload();
- boolean changed = false;
-
- if (oldDevice == null || !equal(oldDevice.getUuid(), newDevice.getUuid())) {
- ret.setUuid(newDevice.getUuid());
- changed = true;
- }
-
- if (oldDevice == null || !equal(oldDevice.getOsName(), newDevice.getOsName())) {
- ret.setOsName(newDevice.getOsName());
- changed = true;
- }
-
- if (oldDevice == null || !equal(oldDevice.getOsVersion(), newDevice.getOsVersion())) {
- ret.setOsVersion(newDevice.getOsVersion());
- changed = true;
- }
-
- if (oldDevice == null || !equal(oldDevice.getOsBuild(), newDevice.getOsBuild())) {
- ret.setOsBuild(newDevice.getOsBuild());
- changed = true;
- }
-
- if (oldDevice == null || oldDevice.getOsApiLevel() != newDevice.getOsApiLevel()) {
- ret.setOsApiLevel(String.valueOf(newDevice.getOsApiLevel()));
- changed = true;
- }
-
- if (oldDevice == null || !equal(oldDevice.getManufacturer(), newDevice.getManufacturer())) {
- ret.setManufacturer(newDevice.getManufacturer());
- changed = true;
- }
-
- if (oldDevice == null || !equal(oldDevice.getModel(), newDevice.getModel())) {
- ret.setModel(newDevice.getModel());
- changed = true;
- }
-
- if (oldDevice == null || !equal(oldDevice.getBoard(), newDevice.getBoard())) {
- ret.setBoard(newDevice.getBoard());
- changed = true;
- }
-
- if (oldDevice == null || !equal(oldDevice.getProduct(), newDevice.getProduct())) {
- ret.setProduct(newDevice.getProduct());
- changed = true;
- }
-
- if (oldDevice == null || !equal(oldDevice.getBrand(), newDevice.getBrand())) {
- ret.setBrand(newDevice.getBrand());
- changed = true;
- }
-
- if (oldDevice == null || !equal(oldDevice.getCpu(), newDevice.getCpu())) {
- ret.setCpu(newDevice.getCpu());
- changed = true;
- }
-
- if (oldDevice == null || !equal(oldDevice.getDevice(), newDevice.getDevice())) {
- ret.setDevice(newDevice.getDevice());
- changed = true;
- }
-
- if (oldDevice == null || !equal(oldDevice.getCarrier(), newDevice.getCarrier())) {
- ret.setCarrier(newDevice.getCarrier());
- changed = true;
- }
-
- if (oldDevice == null || !equal(oldDevice.getCurrentCarrier(), newDevice.getCurrentCarrier())) {
- ret.setCurrentCarrier(newDevice.getCurrentCarrier());
- changed = true;
- }
-
- if (oldDevice == null || !equal(oldDevice.getNetworkType(), newDevice.getNetworkType())) {
- ret.setNetworkType(newDevice.getNetworkType());
- changed = true;
- }
-
- if (oldDevice == null || !equal(oldDevice.getBuildType(), newDevice.getBuildType())) {
- ret.setBuildType(newDevice.getBuildType());
- changed = true;
- }
-
- if (oldDevice == null || !equal(oldDevice.getBuildId(), newDevice.getBuildId())) {
- ret.setBuildId(newDevice.getBuildId());
- changed = true;
- }
-
- if (oldDevice == null || !equal(oldDevice.getBootloaderVersion(), newDevice.getBootloaderVersion())) {
- ret.setBootloaderVersion(newDevice.getBootloaderVersion());
- changed = true;
- }
-
- if (oldDevice == null || !equal(oldDevice.getRadioVersion(), newDevice.getRadioVersion())) {
- ret.setRadioVersion(newDevice.getRadioVersion());
- changed = true;
- }
-
- if (oldDevice == null || !equal(oldDevice.getCustomData(), newDevice.getCustomData())) {
- CustomData customData = newDevice.getCustomData();
- ret.setCustomData(customData != null ? customData.toJson() : null);
- changed = true;
- }
-
- if (oldDevice == null || !equal(oldDevice.getLocaleCountryCode(), newDevice.getLocaleCountryCode())) {
- ret.setLocaleCountryCode(newDevice.getLocaleCountryCode());
- changed = true;
- }
-
- if (oldDevice == null || !equal(oldDevice.getLocaleLanguageCode(), newDevice.getLocaleLanguageCode())) {
- ret.setLocaleLanguageCode(newDevice.getLocaleLanguageCode());
- changed = true;
- }
-
- if (oldDevice == null || !equal(oldDevice.getLocaleRaw(), newDevice.getLocaleRaw())) {
- ret.setLocaleRaw(newDevice.getLocaleRaw());
- changed = true;
- }
-
- if (oldDevice == null || !equal(oldDevice.getUtcOffset(), newDevice.getUtcOffset())) {
- ret.setUtcOffset(newDevice.getUtcOffset());
- changed = true;
- }
-
- if (oldDevice == null || !equal(oldDevice.getAdvertiserId(), newDevice.getAdvertiserId())) {
- ret.setAdvertiserId(newDevice.getAdvertiserId());
- changed = true;
- }
-
- if (oldDevice == null || !equal(oldDevice.getIntegrationConfig(), newDevice.getIntegrationConfig())) {
- IntegrationConfig integrationConfig = newDevice.getIntegrationConfig();
- ret.setIntegrationConfig(integrationConfig != null ? integrationConfig.toJson() : null);
- changed = true;
- }
- return changed ? ret : null;
- }
-
- private static boolean equal(Object a, Object b) {
- return a == null && b == null || a != null && b != null && a.equals(b);
- }
}
+
diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/storage/DevicePayloadDiff.java b/apptentive/src/main/java/com/apptentive/android/sdk/storage/DevicePayloadDiff.java
new file mode 100644
index 000000000..dcd857b8f
--- /dev/null
+++ b/apptentive/src/main/java/com/apptentive/android/sdk/storage/DevicePayloadDiff.java
@@ -0,0 +1,155 @@
+package com.apptentive.android.sdk.storage;
+
+import com.apptentive.android.sdk.model.DevicePayload;
+
+/**
+ * A helper class with static methods for and diffing information about the current device.
+ */
+public final class DevicePayloadDiff {
+
+ public static DevicePayload getDiffPayload(Device oldDevice, Device newDevice) {
+ if (newDevice == null) {
+ return null;
+ }
+
+ DevicePayload ret = new DevicePayload();
+ boolean changed = false;
+
+ if (oldDevice == null || !equal(oldDevice.getUuid(), newDevice.getUuid())) {
+ ret.setUuid(newDevice.getUuid());
+ changed = true;
+ }
+
+ if (oldDevice == null || !equal(oldDevice.getOsName(), newDevice.getOsName())) {
+ ret.setOsName(newDevice.getOsName());
+ changed = true;
+ }
+
+ if (oldDevice == null || !equal(oldDevice.getOsVersion(), newDevice.getOsVersion())) {
+ ret.setOsVersion(newDevice.getOsVersion());
+ changed = true;
+ }
+
+ if (oldDevice == null || !equal(oldDevice.getOsBuild(), newDevice.getOsBuild())) {
+ ret.setOsBuild(newDevice.getOsBuild());
+ changed = true;
+ }
+
+ if (oldDevice == null || oldDevice.getOsApiLevel() != newDevice.getOsApiLevel()) {
+ ret.setOsApiLevel(String.valueOf(newDevice.getOsApiLevel()));
+ changed = true;
+ }
+
+ if (oldDevice == null || !equal(oldDevice.getManufacturer(), newDevice.getManufacturer())) {
+ ret.setManufacturer(newDevice.getManufacturer());
+ changed = true;
+ }
+
+ if (oldDevice == null || !equal(oldDevice.getModel(), newDevice.getModel())) {
+ ret.setModel(newDevice.getModel());
+ changed = true;
+ }
+
+ if (oldDevice == null || !equal(oldDevice.getBoard(), newDevice.getBoard())) {
+ ret.setBoard(newDevice.getBoard());
+ changed = true;
+ }
+
+ if (oldDevice == null || !equal(oldDevice.getProduct(), newDevice.getProduct())) {
+ ret.setProduct(newDevice.getProduct());
+ changed = true;
+ }
+
+ if (oldDevice == null || !equal(oldDevice.getBrand(), newDevice.getBrand())) {
+ ret.setBrand(newDevice.getBrand());
+ changed = true;
+ }
+
+ if (oldDevice == null || !equal(oldDevice.getCpu(), newDevice.getCpu())) {
+ ret.setCpu(newDevice.getCpu());
+ changed = true;
+ }
+
+ if (oldDevice == null || !equal(oldDevice.getDevice(), newDevice.getDevice())) {
+ ret.setDevice(newDevice.getDevice());
+ changed = true;
+ }
+
+ if (oldDevice == null || !equal(oldDevice.getCarrier(), newDevice.getCarrier())) {
+ ret.setCarrier(newDevice.getCarrier());
+ changed = true;
+ }
+
+ if (oldDevice == null || !equal(oldDevice.getCurrentCarrier(), newDevice.getCurrentCarrier())) {
+ ret.setCurrentCarrier(newDevice.getCurrentCarrier());
+ changed = true;
+ }
+
+ if (oldDevice == null || !equal(oldDevice.getNetworkType(), newDevice.getNetworkType())) {
+ ret.setNetworkType(newDevice.getNetworkType());
+ changed = true;
+ }
+
+ if (oldDevice == null || !equal(oldDevice.getBuildType(), newDevice.getBuildType())) {
+ ret.setBuildType(newDevice.getBuildType());
+ changed = true;
+ }
+
+ if (oldDevice == null || !equal(oldDevice.getBuildId(), newDevice.getBuildId())) {
+ ret.setBuildId(newDevice.getBuildId());
+ changed = true;
+ }
+
+ if (oldDevice == null || !equal(oldDevice.getBootloaderVersion(), newDevice.getBootloaderVersion())) {
+ ret.setBootloaderVersion(newDevice.getBootloaderVersion());
+ changed = true;
+ }
+
+ if (oldDevice == null || !equal(oldDevice.getRadioVersion(), newDevice.getRadioVersion())) {
+ ret.setRadioVersion(newDevice.getRadioVersion());
+ changed = true;
+ }
+
+ if (oldDevice == null || !equal(oldDevice.getCustomData(), newDevice.getCustomData())) {
+ CustomData customData = newDevice.getCustomData();
+ ret.setCustomData(customData != null ? customData.toJson() : null);
+ changed = true;
+ }
+
+ if (oldDevice == null || !equal(oldDevice.getLocaleCountryCode(), newDevice.getLocaleCountryCode())) {
+ ret.setLocaleCountryCode(newDevice.getLocaleCountryCode());
+ changed = true;
+ }
+
+ if (oldDevice == null || !equal(oldDevice.getLocaleLanguageCode(), newDevice.getLocaleLanguageCode())) {
+ ret.setLocaleLanguageCode(newDevice.getLocaleLanguageCode());
+ changed = true;
+ }
+
+ if (oldDevice == null || !equal(oldDevice.getLocaleRaw(), newDevice.getLocaleRaw())) {
+ ret.setLocaleRaw(newDevice.getLocaleRaw());
+ changed = true;
+ }
+
+ if (oldDevice == null || !equal(oldDevice.getUtcOffset(), newDevice.getUtcOffset())) {
+ ret.setUtcOffset(newDevice.getUtcOffset());
+ changed = true;
+ }
+
+ if (oldDevice == null || !equal(oldDevice.getAdvertiserId(), newDevice.getAdvertiserId())) {
+ ret.setAdvertiserId(newDevice.getAdvertiserId());
+ changed = true;
+ }
+
+ if (oldDevice == null || !equal(oldDevice.getIntegrationConfig(), newDevice.getIntegrationConfig())) {
+ IntegrationConfig integrationConfig = newDevice.getIntegrationConfig();
+ ret.setIntegrationConfig(integrationConfig != null ? integrationConfig.toJson() : null);
+ changed = true;
+ }
+ return changed ? ret : null;
+ }
+
+ private static boolean equal(Object a, Object b) {
+ return a == null && b == null || a != null && b != null && a.equals(b);
+ }
+}
diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/util/Constants.java b/apptentive/src/main/java/com/apptentive/android/sdk/util/Constants.java
index 4a03f626b..45090b7d8 100644
--- a/apptentive/src/main/java/com/apptentive/android/sdk/util/Constants.java
+++ b/apptentive/src/main/java/com/apptentive/android/sdk/util/Constants.java
@@ -9,7 +9,7 @@
public class Constants {
public static final int API_VERSION = 9;
- private static final String APPTENTIVE_SDK_VERSION = "5.4.2";
+ private static final String APPTENTIVE_SDK_VERSION = "5.4.3";
public static final int DEFAULT_CONNECT_TIMEOUT_MILLIS = 45000;
public static final int DEFAULT_READ_TIMEOUT_MILLIS = 45000;
diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/util/StringUtils.java b/apptentive/src/main/java/com/apptentive/android/sdk/util/StringUtils.java
index 8df2c0b85..9c76ae3aa 100644
--- a/apptentive/src/main/java/com/apptentive/android/sdk/util/StringUtils.java
+++ b/apptentive/src/main/java/com/apptentive/android/sdk/util/StringUtils.java
@@ -34,6 +34,8 @@
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.Random;
+import java.util.UUID;
/**
* A collection of useful string-related functions
@@ -234,4 +236,16 @@ public static int parseInt(String value, int defaultValue) {
}
//endregion
+
+ //region Device identifiers
+
+ public static String randomAndroidID() {
+ Random random = new Random();
+ long lo = ((long) random.nextInt()) & 0xffffffffL;
+ long hi = ((long) random.nextInt()) << 32L;
+ long number = hi | lo;
+ return Long.toHexString(number);
+ }
+
+ //endregion
}
diff --git a/apptentive/src/main/java/com/apptentive/android/sdk/util/Util.java b/apptentive/src/main/java/com/apptentive/android/sdk/util/Util.java
index 5395c1dca..ac2130421 100644
--- a/apptentive/src/main/java/com/apptentive/android/sdk/util/Util.java
+++ b/apptentive/src/main/java/com/apptentive/android/sdk/util/Util.java
@@ -1118,7 +1118,7 @@ public static String humanReadableByteCount(long bytes, boolean si) {
return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);
}
- public static String getAndroidId(Context context) {
+ public static String getAndroidID(Context context) {
if (context == null) {
return null;
}
diff --git a/build.gradle b/build.gradle
index 0fd28f57c..a9784273f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -6,7 +6,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.4.0'
+ classpath 'com.android.tools.build:gradle:3.4.1'
classpath 'com.github.3mph4515:gradle-hockeyapp-plugin:3.7.6'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
diff --git a/samples/apptentive-example/build.gradle b/samples/apptentive-example/build.gradle
index 390acd4ab..c18e7b375 100644
--- a/samples/apptentive-example/build.gradle
+++ b/samples/apptentive-example/build.gradle
@@ -16,7 +16,7 @@ repositories {
}
dependencies {
- implementation 'com.apptentive:apptentive-android:5.3.3'
+ implementation 'com.apptentive:apptentive-android:5.4.2'
implementation 'com.google.firebase:firebase-messaging:17.3.4'
}