Skip to content

Commit

Permalink
fix: modify() call throws an exception when user is not present
Browse files Browse the repository at this point in the history
When the AdId updates, we will generate a modify() request interanlly with the current user. When the current user is not present/null, this request currently fails with an error log or a thrown exception, if the SDK is running in Development mode. In order to avoid losing this modify request or causing an exception, we will defer the modify request until a user is present, if it is not already
  • Loading branch information
willpassidomo committed Jul 1, 2022
1 parent bdf2476 commit bb8b552
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 25 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.mparticle.internal

import com.mparticle.MParticle
import com.mparticle.MParticleOptions
import com.mparticle.identity.BaseIdentityTask
import com.mparticle.identity.IdentityApiRequest
import com.mparticle.testutils.BaseCleanInstallEachTest
import com.mparticle.testutils.MPLatch
import org.junit.Test
import kotlin.test.assertEquals
import kotlin.test.assertNull

class UpdateAdIdIdentityTest : BaseCleanInstallEachTest() {

@Test
fun testAdIdModifyNoUser() {
// setup mock server so initial identity request will not set mpid
mServer.setupHappyIdentify(0)
val latch = MPLatch(1)
MParticle.start(
MParticleOptions.builder(mContext)
.credentials("key", "secret")
.identifyTask(BaseIdentityTask().addSuccessListener { latch.countDown() })
.build()
)

// execute CheckAdIdRunnable without a current user
AppStateManager.CheckAdIdRunnable("newAdId", "oldAdId").run()
assertNull(MParticle.getInstance()!!.Identity().currentUser)

// set a current user
mServer.addConditionalIdentityResponse(0, mStartingMpid)
latch.await()

// force a modify request to ensure that the modify request from the CheckAdIdRunnable is completed
val latch2 = MPLatch(1)
MParticle.getInstance()!!.Identity().modify(IdentityApiRequest.withEmptyUser().customerId("someId").build())
.addSuccessListener { latch2.countDown() }
latch2.await()

// check that modify request from CheckAdIdRunnable executed when current user was set
mServer.Requests().modify.count { request ->
request.asIdentityRequest().body.identity_changes.let {
it.size == 1 &&
it[0].let { identityChange ->
identityChange["new_value"] == "newAdId" &&
identityChange["old_value"] == "oldAdId"
}
}
}.let {
assertEquals(1, it)
}
}
}
12 changes: 12 additions & 0 deletions android-core/src/main/java/com/mparticle/identity/IdentityApi.java
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,18 @@ public void run() {
}
}

public static abstract class SingleUserIdentificationCallback implements IdentityStateListener {

@Override
public void onUserIdentified(MParticleUser user, MParticleUser previousUser) {
MParticle.getInstance().Identity().removeIdentityStateListener(this);
onUserFound(user);
}

public abstract void onUserFound(MParticleUser user);

}

/**
* @hidden
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import android.os.Handler;
import android.os.SystemClock;

import androidx.annotation.Nullable;

import com.mparticle.MPEvent;
import com.mparticle.MParticle;
import com.mparticle.identity.IdentityApi;
Expand Down Expand Up @@ -171,7 +173,9 @@ public void onActivityResumed(Activity activity) {
initialize(mCurrentActivityName, previousSessionUri, previousSessionParameters, previousSessionPackage);
} else if (isBackgrounded() && mLastStoppedTime.get() > 0) {
isBackToForeground = true;
mMessageManager.postToMessageThread(new CheckAdIdRunnable());
MPUtility.AdIdInfo adIdInfo = MPUtility.getAdIdInfo(mContext);
String currentGoogleAdId = adIdInfo == null ? null : adIdInfo.id;
mMessageManager.postToMessageThread(new CheckAdIdRunnable(currentGoogleAdId, mConfigManager.getPreviousAdId()));
logStateTransition(Constants.StateTransitionType.STATE_TRANS_FORE,
mCurrentActivityName,
mLastStoppedTime.get() - mLastForegroundTime,
Expand Down Expand Up @@ -441,33 +445,43 @@ public WeakReference<Activity> getCurrentActivity() {
return mCurrentActivityReference;
}

class CheckAdIdRunnable implements Runnable {
static class CheckAdIdRunnable implements Runnable {
String currentAdId;
String previousAdId;

CheckAdIdRunnable(@Nullable String currentAdId, @Nullable String previousAdId) {
this.currentAdId = currentAdId;
this.previousAdId = previousAdId;
}

@Override
public void run() {
String previousGoogleAdId = mConfigManager.getPreviousAdId();
MPUtility.AdIdInfo adIdInfo = MPUtility.getAdIdInfo(mContext);
String currentGoogleAdId = adIdInfo == null ? null : adIdInfo.id;
if (currentGoogleAdId != null && !currentGoogleAdId.equals(previousGoogleAdId)) {
if (currentAdId != null && !currentAdId.equals(previousAdId)) {
MParticle instance = MParticle.getInstance();
if (instance != null) {
MParticleUser user = instance.Identity().getCurrentUser();

Builder builder;
if (user != null) {
builder = new Builder(user);
instance.Identity().modify(new Builder(user)
.googleAdId(currentAdId, previousAdId)
.build());
} else {
builder = new Builder();
instance.Identity().addIdentityStateListener(new IdentityApi.SingleUserIdentificationCallback() {
@Override
public void onUserFound(MParticleUser user) {
instance.Identity().modify(new Builder(user)
.googleAdId(currentAdId, previousAdId)
.build());
}
});
}
instance.Identity().modify(builder
.googleAdId(currentGoogleAdId, previousGoogleAdId)
.build());

}
}
}
}

class Builder extends IdentityApiRequest.Builder {
static class Builder extends IdentityApiRequest.Builder {
Builder(MParticleUser user) {
super(user);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
import com.mparticle.commerce.Product;
import com.mparticle.commerce.Promotion;
import com.mparticle.commerce.TransactionAttributes;
import com.mparticle.identity.IdentityApi;
import com.mparticle.identity.IdentityApi.SingleUserIdentificationCallback;
import com.mparticle.identity.IdentityApiRequest;
import com.mparticle.identity.IdentityStateListener;
import com.mparticle.identity.MParticleUser;
Expand Down Expand Up @@ -822,18 +824,6 @@ private MParticle.IdentityType getIdentityType(JSONObject object) {
return identityType;
}

abstract class SingleUserIdentificationCallback implements IdentityStateListener {

@Override
public void onUserIdentified(MParticleUser user, MParticleUser previousUser) {
MParticle.getInstance().Identity().removeIdentityStateListener(this);
onUserFound(user);
}

abstract void onUserFound(MParticleUser user);

}

public static void registerWebView(WebView webView, String workspaceToken) {
if (webView != null) {
String bridgeName = getBridgeName(workspaceToken);
Expand Down

0 comments on commit bb8b552

Please sign in to comment.