Skip to content

Commit f8bb6cf

Browse files
committed
Merge pull request #323 from Iterable/MOB-2606-read-state
[MOB-2606] persistent read state for inbox in-apps # Conflicts: # iterableapi/src/main/java/com/iterable/iterableapi/IterableInAppManager.java
1 parent c6865c1 commit f8bb6cf

File tree

9 files changed

+127
-14
lines changed

9 files changed

+127
-14
lines changed

.gitignore

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,7 @@ google-services.json
5454
# Freeline
5555
freeline.py
5656
freeline/
57-
freeline_project_description.json
57+
freeline_project_description.json
58+
59+
# MacOS generated files
60+
.DS_Store

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

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,8 @@ public void execute(String payload) {
179179
} catch (JSONException e) {
180180
IterableLogger.e(TAG, e.toString());
181181
}
182+
} else {
183+
scheduleProcessing();
182184
}
183185
}
184186
});
@@ -305,20 +307,38 @@ private boolean isMessageExpired(IterableInAppMessage message) {
305307
private void syncWithRemoteQueue(List<IterableInAppMessage> remoteQueue) {
306308
boolean changed = false;
307309
Map<String, IterableInAppMessage> remoteQueueMap = new HashMap<>();
310+
308311
for (IterableInAppMessage message : remoteQueue) {
309312
remoteQueueMap.put(message.getMessageId(), message);
310-
if (storage.getMessage(message.getMessageId()) == null) {
313+
314+
boolean isInAppStored = storage.getMessage(message.getMessageId()) != null;
315+
316+
if (!isInAppStored) {
311317
storage.addMessage(message);
312318
onMessageAdded(message);
313319
changed = true;
314320
}
321+
322+
if (isInAppStored) {
323+
IterableInAppMessage localMessage = storage.getMessage(message.getMessageId());
324+
325+
boolean shouldOverwriteInApp = !localMessage.isRead() && message.isRead();
326+
327+
if (shouldOverwriteInApp) {
328+
localMessage.setRead(message.isRead());
329+
330+
changed = true;
331+
}
332+
}
315333
}
334+
316335
for (IterableInAppMessage localMessage : storage.getMessages()) {
317336
if (!remoteQueueMap.containsKey(localMessage.getMessageId())) {
318337
storage.removeMessage(localMessage);
319338
changed = true;
320339
}
321340
}
341+
322342
scheduleProcessing();
323343
if (changed) {
324344
notifyOnChange();
@@ -386,9 +406,10 @@ private void handleIterableCustomAction(String actionName, IterableInAppMessage
386406

387407
@Override
388408
public void onSwitchToForeground() {
389-
scheduleProcessing();
390409
if (IterableUtil.currentTimeMillis() - lastSyncTime > MOVE_TO_FOREGROUND_SYNC_INTERVAL_MS) {
391410
syncInApp();
411+
} else {
412+
scheduleProcessing();
392413
}
393414
}
394415

iterableapi/src/test/java/com/iterable/iterableapi/IterableInAppManagerTest.java

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import androidx.annotation.NonNull;
88
import androidx.fragment.app.FragmentActivity;
99

10+
import java.util.List;
11+
1012
import com.iterable.iterableapi.unit.PathBasedQueueDispatcher;
1113

1214
import org.json.JSONArray;
@@ -161,15 +163,14 @@ public void testReset() throws Exception {
161163
@Test
162164
public void testProcessAfterForeground() throws Exception {
163165
dispatcher.enqueueResponse("/inApp/getMessages", new MockResponse().setBody(IterableTestUtils.getResourceString("inapp_payload_single.json")));
164-
IterableInAppManager inAppManager = IterableApi.getInstance().getInAppManager();
165-
assertEquals(0, inAppManager.getMessages().size());
166166

167-
inAppManager.syncInApp();
167+
ActivityController<Activity> activityController = Robolectric.buildActivity(Activity.class).create().start().resume();
168168
shadowOf(getMainLooper()).idle();
169-
assertEquals(1, inAppManager.getMessages().size());
169+
shadowOf(getMainLooper()).runToEndOfTasks();
170170

171-
ActivityController<Activity> activityController = Robolectric.buildActivity(Activity.class).create().start().resume();
171+
IterableInAppManager inAppManager = IterableApi.getInstance().getInAppManager();
172172
shadowOf(getMainLooper()).idle();
173+
assertEquals(1, inAppManager.getMessages().size());
173174

174175
ArgumentCaptor<IterableInAppMessage> inAppMessageCaptor = ArgumentCaptor.forClass(IterableInAppMessage.class);
175176
verify(inAppHandler).onNewInApp(inAppMessageCaptor.capture());
@@ -382,12 +383,30 @@ public void testInAppAutoDisplayPause() throws Exception {
382383
verify(inAppHandler, times(1)).onNewInApp(inAppMessageCaptor.capture());
383384
}
384385

386+
@Test
387+
public void testMessagePersistentReadStateFromServer() throws Exception {
388+
// load the in-app that has not been synchronized with the server yet (read state is set to false)
389+
dispatcher.enqueueResponse("/inApp/getMessages", new MockResponse().setBody(IterableTestUtils.getResourceString("inapp_payload_inbox_read_state_1.json")));
390+
IterableInAppManager inAppManager = IterableApi.getInstance().getInAppManager();
391+
inAppManager.syncInApp();
392+
shadowOf(getMainLooper()).idle();
393+
394+
List<IterableInAppMessage> inboxMessages = inAppManager.getInboxMessages();
395+
assertFalse(inboxMessages.get(0).isRead());
396+
397+
// now load the one that has the in-app with read state set to true
398+
dispatcher.enqueueResponse("/inApp/getMessages", new MockResponse().setBody(IterableTestUtils.getResourceString("inapp_payload_inbox_read_state_2.json")));
399+
inAppManager.syncInApp();
400+
shadowOf(getMainLooper()).idle();
401+
402+
assertTrue(inboxMessages.get(0).isRead());
403+
}
404+
385405
private static class IterableSkipInAppHandler implements IterableInAppHandler {
386406
@NonNull
387407
@Override
388408
public InAppResponse onNewInApp(@NonNull IterableInAppMessage message) {
389409
return InAppResponse.SKIP;
390410
}
391411
}
392-
393412
}

iterableapi/src/test/java/com/iterable/iterableapi/IterableInAppMessageTest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,15 @@ public void testInAppMessageOnChangeListener_consumed() throws Exception {
7979
verify(mockChangeListener).onInAppMessageChanged(testInAppMessage);
8080
}
8181

82+
@Test
83+
public void testInAppMessageOnChangeListener_read() throws Exception {
84+
IterableInAppMessage testInAppMessage = InAppTestUtils.getTestInAppMessage();
85+
IterableInAppMessage.OnChangeListener mockChangeListener = mock(IterableInAppMessage.OnChangeListener.class);
86+
testInAppMessage.setOnChangeListener(mockChangeListener);
87+
88+
testInAppMessage.setRead(true);
89+
verify(mockChangeListener).onInAppMessageChanged(testInAppMessage);
90+
}
8291

8392
@Test
8493
public void testStorageNotInvoked() throws Exception {

iterableapi/src/test/java/com/iterable/iterableapi/IterableInboxTest.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -127,13 +127,9 @@ public IterableConfig.Builder run(IterableConfig.Builder builder) {
127127
return builder.setInAppHandler(inAppHandler).setCustomActionHandler(customActionHandler).setUrlHandler(urlHandler);
128128
}
129129
});
130-
inAppManager.syncInApp();
131-
shadowOf(getMainLooper()).idle();
132-
133-
assertEquals(2, inAppManager.getInboxMessages().size());
134-
assertEquals(2, inAppManager.getUnreadInboxMessagesCount());
135130

136131
Robolectric.buildActivity(Activity.class).create().start().resume();
132+
shadowOf(getMainLooper()).idle();
137133

138134
verify(inAppDisplayerMock).showMessage(any(IterableInAppMessage.class), eq(IterableInAppLocation.IN_APP), any(IterableHelper.IterableUrlCallback.class));
139135

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"inAppMessages": [
3+
{
4+
"messageId": "readMessage1",
5+
"read": false,
6+
"content": {
7+
"html": "<html><head></head><body>Test</body></html>",
8+
"inAppDisplaySettings": {
9+
"top": {
10+
"percentage": 0
11+
},
12+
"right": {
13+
"percentage": 0
14+
},
15+
"bottom": {
16+
"percentage": 0
17+
},
18+
"left": {
19+
"percentage": 0
20+
}
21+
}
22+
},
23+
"saveToInbox": true,
24+
"inboxMetadata": {
25+
"title": "Title",
26+
"subtitle": "Subtitle",
27+
"icon": "icon.png"
28+
}
29+
}
30+
]
31+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"inAppMessages": [
3+
{
4+
"messageId": "readMessage1",
5+
"read": true,
6+
"content": {
7+
"html": "<html><head></head><body>Test</body></html>",
8+
"inAppDisplaySettings": {
9+
"top": {
10+
"percentage": 0
11+
},
12+
"right": {
13+
"percentage": 0
14+
},
15+
"bottom": {
16+
"percentage": 0
17+
},
18+
"left": {
19+
"percentage": 0
20+
}
21+
}
22+
},
23+
"saveToInbox": true,
24+
"inboxMetadata": {
25+
"title": "Title",
26+
"subtitle": "Subtitle",
27+
"icon": "icon.png"
28+
}
29+
}
30+
]
31+
}

iterableapi/src/test/resources/inapp_payload_inbox_show.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"inAppMessages": [
33
{
44
"messageId": "message1",
5+
"read": false,
56
"trigger": {
67
"type": "immediate"
78
},
@@ -28,6 +29,7 @@
2829
}
2930
},{
3031
"messageId": "message2",
32+
"read": false,
3133
"trigger": {
3234
"type": "immediate"
3335
},

iterableapi/src/test/resources/inapp_payload_single.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
{
44
"messageId": "7kx2MmoGdCpuZao9fDueuQoXVAZuDaVV",
55
"expiresAt": 1949157312395,
6+
"read": false,
67
"trigger": {
78
"type": "immediate"
89
},

0 commit comments

Comments
 (0)