Skip to content

Commit 6ba53db

Browse files
authored
Merge branch 'embedded' into master
2 parents 1ed0c34 + 7a9a853 commit 6ba53db

21 files changed

+1527
-7
lines changed

.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,4 +65,6 @@ pom.xml.tag
6565
pom.xml.releaseBackup
6666
pom.xml.versionsBackup
6767
pom.xml.next
68-
release.properties
68+
release.properties
69+
70+
jacoco.exec

iterableapi/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ dependencies {
4646
testImplementation 'androidx.test.ext:junit:1.1.2'
4747
testImplementation 'androidx.test:rules:1.3.0'
4848
testImplementation 'org.mockito:mockito-core:3.3.3'
49+
testImplementation 'org.mockito:mockito-inline:2.8.47'
4950
testImplementation 'org.robolectric:robolectric:4.4'
5051
testImplementation 'org.robolectric:shadows-playservices:4.4'
5152
testImplementation 'org.khronos:opengl-api:gl1.1-android-2.1_r1'

iterableapi/src/androidTest/java/com/iterable/iterableapi/IterableTestUtils.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
public class IterableTestUtils {
77
public static void createIterableApi() {
88
IterableApi.sharedInstance = new IterableApi(mock(IterableInAppManager.class));
9-
initIterableApi(null);
9+
IterableConfig config = new IterableConfig.Builder().build();
10+
initIterableApi(config);
1011
IterableApi.getInstance().setEmail("test_email");
1112
}
1213

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.iterable.iterableapi
2+
3+
import androidx.annotation.RestrictTo
4+
import java.util.Date
5+
6+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
7+
data class EmbeddedImpressionData(
8+
val messageId: String,
9+
var displayCount: Int = 0,
10+
var duration: Float = 0.0f,
11+
var start: Date? = null
12+
) {
13+
constructor(
14+
messageId: String
15+
) : this(messageId, 0, 0.0f, null)
16+
}
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package com.iterable.iterableapi
2+
3+
import androidx.annotation.RestrictTo
4+
import java.util.Date
5+
6+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
7+
public class EmbeddedSessionManager {
8+
9+
private val TAG = "EmbeddedSessionManager"
10+
11+
private var impressions: MutableMap<String, EmbeddedImpressionData> = mutableMapOf()
12+
13+
var session: IterableEmbeddedSession = IterableEmbeddedSession(
14+
null,
15+
null,
16+
"0",
17+
null
18+
)
19+
20+
fun isTracking(): Boolean {
21+
return session.start != null
22+
}
23+
24+
fun startSession() {
25+
if (isTracking()) {
26+
IterableLogger.e(TAG, "Embedded session started twice")
27+
return
28+
}
29+
30+
session = IterableEmbeddedSession(
31+
Date(),
32+
null,
33+
"0",
34+
null
35+
)
36+
}
37+
38+
fun endSession() {
39+
if (!isTracking()) {
40+
IterableLogger.e(TAG, "Embedded session ended without start")
41+
return
42+
}
43+
44+
if(impressions.isNotEmpty()) {
45+
endAllImpressions()
46+
47+
val sessionToTrack = IterableEmbeddedSession(
48+
session.start,
49+
Date(),
50+
"0",
51+
getImpressionList()
52+
)
53+
54+
IterableApi.getInstance().trackEmbeddedSession(sessionToTrack)
55+
56+
//reset session for next session start
57+
session = IterableEmbeddedSession(
58+
null,
59+
null,
60+
"0",
61+
null
62+
)
63+
64+
impressions = mutableMapOf()
65+
}
66+
}
67+
68+
fun startImpression(messageId: String) {
69+
var impressionData: EmbeddedImpressionData? = impressions[messageId]
70+
71+
if (impressionData == null) {
72+
impressionData = EmbeddedImpressionData(messageId)
73+
impressions[messageId] = impressionData
74+
}
75+
76+
impressionData.start = Date()
77+
}
78+
79+
fun pauseImpression(messageId: String) {
80+
val impressionData: EmbeddedImpressionData? = impressions[messageId]
81+
82+
if (impressionData == null) {
83+
IterableLogger.e(TAG, "onMessageImpressionEnded: impressionData not found")
84+
return
85+
}
86+
87+
if (impressionData.start == null) {
88+
IterableLogger.e(TAG, "onMessageImpressionEnded: impressionStarted is null")
89+
return
90+
}
91+
92+
updateDisplayCountAndDuration(impressionData)
93+
}
94+
95+
private fun endAllImpressions() {
96+
for (impressionData in impressions.values) {
97+
updateDisplayCountAndDuration(impressionData)
98+
}
99+
}
100+
101+
private fun getImpressionList(): List<IterableEmbeddedImpression>? {
102+
val impressionList: MutableList<IterableEmbeddedImpression> = ArrayList()
103+
for (impressionData in impressions.values) {
104+
impressionList.add(
105+
IterableEmbeddedImpression(
106+
impressionData.messageId,
107+
impressionData.displayCount,
108+
impressionData.duration
109+
)
110+
)
111+
}
112+
return impressionList
113+
}
114+
115+
private fun updateDisplayCountAndDuration(impressionData: EmbeddedImpressionData): EmbeddedImpressionData {
116+
if (impressionData.start != null) {
117+
impressionData.displayCount = impressionData.displayCount.plus(1)
118+
impressionData.duration =
119+
impressionData.duration.plus((Date().time - impressionData.start!!.time) / 1000.0)
120+
.toFloat()
121+
impressionData.start = null
122+
}
123+
return impressionData
124+
}
125+
}

iterableapi/src/main/java/com/iterable/iterableapi/IterableApi.java

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ public class IterableApi {
4545

4646
IterableApiClient apiClient = new IterableApiClient(new IterableApiAuthProvider());
4747
private @Nullable IterableInAppManager inAppManager;
48+
private @Nullable IterableEmbeddedManager embeddedManager;
4849
private String inboxSessionId;
4950
private IterableAuthManager authManager;
5051
private HashMap<String, String> deviceAttributes = new HashMap<>();
@@ -225,6 +226,28 @@ void getInAppMessages(int count, @NonNull IterableHelper.IterableActionHandler o
225226
apiClient.getInAppMessages(count, onCallback);
226227
}
227228

229+
/**
230+
* A package-private method to get a list of Embedded Messages from Iterable;
231+
* Passes the result to the callback.
232+
* To get list of messages as a list of EmbeddedMessages in memory, use
233+
* {@link IterableEmbeddedManager#getEmbeddedMessages()} instead
234+
*
235+
* @param onCallback
236+
*/
237+
void getEmbeddedMessages(@NonNull IterableHelper.IterableActionHandler onCallback) {
238+
if (!checkSDKInitialization()) {
239+
return;
240+
}
241+
apiClient.getEmbeddedMessages(onCallback);
242+
}
243+
244+
void getEmbeddedMessages(@NonNull IterableHelper.SuccessHandler onSuccess, @NonNull IterableHelper.FailureHandler onFailure) {
245+
if (!checkSDKInitialization()) {
246+
return;
247+
}
248+
apiClient.getEmbeddedMessages(onSuccess, onFailure);
249+
}
250+
228251
/**
229252
* Tracks in-app delivery events (per in-app)
230253
* @param message the in-app message to be tracked as delivered */
@@ -241,6 +264,22 @@ void trackInAppDelivery(@NonNull IterableInAppMessage message) {
241264
apiClient.trackInAppDelivery(message);
242265
}
243266

267+
/**
268+
* Tracks embedded message received events (per embedded message)
269+
* @param message the embedded message to be tracked as received */
270+
void trackEmbeddedMessageReceived(@NonNull IterableEmbeddedMessage message) {
271+
if (!checkSDKInitialization()) {
272+
return;
273+
}
274+
275+
if (message == null) {
276+
IterableLogger.e(TAG, "trackEmbeddedMessageReceived: message is null");
277+
return;
278+
}
279+
280+
apiClient.trackEmbeddedMessageReceived(message);
281+
}
282+
244283
private String getPushIntegrationName() {
245284
if (config.pushIntegrationName != null) {
246285
return config.pushIntegrationName;
@@ -512,6 +551,10 @@ public static void initialize(@NonNull Context context, @NonNull String apiKey,
512551
sharedInstance.config.useInMemoryStorageForInApps);
513552
}
514553

554+
if (sharedInstance.embeddedManager == null) {
555+
sharedInstance.embeddedManager = new IterableEmbeddedManager(null, null);
556+
}
557+
515558
loadLastSavedConfiguration(context);
516559
IterablePushNotificationUtil.processPendingAction(context);
517560
if (DeviceInfoUtils.isFireTV(context.getPackageManager())) {
@@ -541,12 +584,20 @@ public static void setContext(Context context) {
541584
this.inAppManager = inAppManager;
542585
}
543586

587+
@VisibleForTesting
588+
IterableApi(IterableInAppManager inAppManager, IterableEmbeddedManager embeddedManager) {
589+
config = new IterableConfig.Builder().build();
590+
this.inAppManager = inAppManager;
591+
this.embeddedManager = embeddedManager;
592+
}
593+
544594
@VisibleForTesting
545595
IterableApi(IterableApiClient apiClient, IterableInAppManager inAppManager) {
546596
config = new IterableConfig.Builder().build();
547597
this.apiClient = apiClient;
548598
this.inAppManager = inAppManager;
549599
}
600+
550601
//endregion
551602

552603
//region SDK public functions
@@ -564,6 +615,15 @@ public IterableInAppManager getInAppManager() {
564615
return inAppManager;
565616
}
566617

618+
@NonNull
619+
public IterableEmbeddedManager embeddedManager() {
620+
if (embeddedManager == null) {
621+
throw new RuntimeException("IterableApi must be initialized before calling getFlexManager(). " +
622+
"Make sure you call IterableApi#initialize() in Application#onCreate");
623+
}
624+
return embeddedManager;
625+
}
626+
567627
/**
568628
* Returns the attribution information ({@link IterableAttributionInfo}) for last push open
569629
* or app link click from an email.
@@ -1089,6 +1149,26 @@ public void trackInAppClose(@NonNull IterableInAppMessage message, @Nullable Str
10891149

10901150
apiClient.trackInAppClose(message, clickedURL, closeAction, clickLocation, inboxSessionId);
10911151
}
1152+
1153+
/**
1154+
* Tracks when a link inside an embedded message is clicked
1155+
* @param message the embedded message to be tracked
1156+
* @param buttonIdentifier identifier that determines which button or if embedded message itself was clicked
1157+
* @param clickedUrl the URL of the clicked button or assigned to the embedded message itself
1158+
*/
1159+
public void trackEmbeddedClick(@NonNull IterableEmbeddedMessage message, @Nullable String buttonIdentifier, @Nullable String clickedUrl) {
1160+
if (!checkSDKInitialization()) {
1161+
return;
1162+
}
1163+
1164+
if (message == null) {
1165+
IterableLogger.e(TAG, "trackEmbeddedClick: message is null");
1166+
return;
1167+
}
1168+
1169+
apiClient.trackEmbeddedClick(message, buttonIdentifier, clickedUrl);
1170+
}
1171+
10921172
//endregion
10931173

10941174
//region DEPRECATED - API public functions
@@ -1203,5 +1283,24 @@ public void setInboxSessionId(@Nullable String inboxSessionId) {
12031283
public void clearInboxSessionId() {
12041284
this.inboxSessionId = null;
12051285
}
1286+
1287+
@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
1288+
public void trackEmbeddedSession(@NonNull IterableEmbeddedSession session) {
1289+
if (!checkSDKInitialization()) {
1290+
return;
1291+
}
1292+
1293+
if (session == null) {
1294+
IterableLogger.e(TAG, "trackEmbeddedSession: session is null");
1295+
return;
1296+
}
1297+
1298+
if (session.getStart() == null || session.getEnd() == null) {
1299+
IterableLogger.e(TAG, "trackEmbeddedSession: sessionStartTime and sessionEndTime must be set");
1300+
return;
1301+
}
1302+
1303+
apiClient.trackEmbeddedSession(session);
1304+
}
12061305
//endregion
12071306
}

0 commit comments

Comments
 (0)