Skip to content

Commit c6c0a32

Browse files
committed
Remove IAM from db
* Remove IAMs with redisplay from DB when lastDisplay is older than six month
1 parent c3f3c1b commit c6c0a32

File tree

8 files changed

+127
-66
lines changed

8 files changed

+127
-66
lines changed

OneSignalSDK/onesignal/src/main/java/com/onesignal/OSInAppMessageController.java

Lines changed: 42 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class OSInAppMessageController implements OSDynamicTriggerControllerObserver, OS
3030

3131
public static final String IN_APP_MESSAGES_JSON_KEY = "in_app_messages";
3232
private static final String OS_SAVE_IN_APP_MESSAGE = "OS_SAVE_IN_APP_MESSAGE";
33+
private static final String OS_DELETE_IN_APP_MESSAGE = "OS_DELETE_IN_APP_MESSAGE";
3334

3435
OSTriggerController triggerController;
3536
private OSSystemConditionController systemConditionController;
@@ -49,7 +50,8 @@ class OSInAppMessageController implements OSDynamicTriggerControllerObserver, OS
4950
// Ordered IAMs queued to display, includes the message currently displaying, if any.
5051
@NonNull final ArrayList<OSInAppMessage> messageDisplayQueue;
5152
// IAMs displayed with last displayed time and quantity of displays data
52-
@NonNull private List<OSInAppMessage> displayedMessagesData;
53+
// This is retrieved from a DB Table that take care of each object to be unique
54+
@NonNull private List<OSInAppMessage> redisplayedInAppMessages;
5355

5456
boolean inAppMessagingEnabled = true;
5557
boolean inAppMessageShowing = false;
@@ -110,9 +112,9 @@ protected OSInAppMessageController(OneSignalDbHelper dbInstance) {
110112

111113
void initRedisplayData(OneSignalDbHelper dbInstance) {
112114
inAppMessageRepository = new OSInAppMessageRepository(dbInstance);
113-
displayedMessagesData = inAppMessageRepository.getAllInAppMessages();
115+
redisplayedInAppMessages = inAppMessageRepository.getRedisplayedInAppMessages();
114116

115-
OneSignal.Log(OneSignal.LOG_LEVEL.DEBUG, "displayedMessagesData: " + displayedMessagesData.toString());
117+
OneSignal.Log(OneSignal.LOG_LEVEL.DEBUG, "redisplayedInAppMessages: " + redisplayedInAppMessages.toString());
116118
}
117119

118120
// Normally we wait until on_session call to download the latest IAMs
@@ -151,6 +153,15 @@ void receivedInAppMessageJson(@NonNull JSONArray json) throws JSONException {
151153
json.toString());
152154

153155
processInAppMessageJson(json);
156+
157+
// Remove cache redisplayed messages
158+
new Thread(new Runnable() {
159+
@Override
160+
public void run() {
161+
Thread.currentThread().setPriority(Process.THREAD_PRIORITY_BACKGROUND);
162+
inAppMessageRepository.deleteOldRedisplayedInAppMessages();
163+
}
164+
}, OS_DELETE_IN_APP_MESSAGE).start();
154165
}
155166

156167
private void processInAppMessageJson(@NonNull JSONArray json) throws JSONException {
@@ -291,13 +302,15 @@ private void fireRESTCallForClick(@NonNull final OSInAppMessage message, @NonNul
291302
return;
292303

293304
final String clickId = action.clickId;
305+
// If IAM has redisplay the clickId may be available
294306
boolean clickAvailableByRedisplay = message.getDisplayStats().isRedisplayEnabled() && message.isClickAvailable(clickId);
295307

296308
// Never count multiple clicks for the same click UUID unless that click is from an IAM with redisplay
297309
if (!clickAvailableByRedisplay && clickedClickIds.contains(clickId))
298310
return;
299311

300312
clickedClickIds.add(clickId);
313+
// Track clickId per IAM
301314
message.addClickId(clickId);
302315

303316
try {
@@ -338,26 +351,26 @@ void onFailure(int statusCode, String response, Throwable throwable) {
338351
/**
339352
* Part of redisplay logic
340353
*
341-
* In order to an IAM to be re display, the following conditions need to be satisfied
342-
* - IAM has redisplay property
343-
* - Gap between displays is satisfied
344-
* - Quantity of displays is available
345-
* - Some IAM Trigger was fired
354+
* In order to redisplay an IAM, the following conditions must be satisfied:
355+
* 1. IAM has redisplay property
356+
* 2. Time delay between redisplay satisfied
357+
* 3. Has more redisplays
358+
* 4. An IAM trigger was satisfied
346359
*
347-
* For re display, the message need to be removed from the arrays that track the display/impression
360+
* For redisplay, the message need to be removed from the arrays that track the display/impression
348361
* For click counting, every message has it click id array
349362
* */
350363
private void setDataForRedisplay(OSInAppMessage message) {
351364
if (!message.getDisplayStats().isRedisplayEnabled())
352365
return;
353366

354367
boolean messageDismissed = dismissedMessages.contains(message.messageId);
355-
int index = displayedMessagesData.indexOf(message);
368+
int index = redisplayedInAppMessages.indexOf(message);
356369

357370
if (messageDismissed && index != -1) {
358371
OneSignal.onesignalLog(OneSignal.LOG_LEVEL.DEBUG, "setDataForRedisplay: " + message.messageId);
359372

360-
OSInAppMessage savedIAM = displayedMessagesData.get(index);
373+
OSInAppMessage savedIAM = redisplayedInAppMessages.get(index);
361374
message.getDisplayStats().setDisplayStats(savedIAM.getDisplayStats());
362375

363376
// Check if conditions are correct for redisplay
@@ -431,7 +444,7 @@ void messageWasDismissed(@NonNull OSInAppMessage message) {
431444

432445
// Don't keep track of last displayed time for a preview
433446
lastTimeInAppDismissed = new Date();
434-
persisIAMessageForRedisplay(message);
447+
persistInAppMessageForRedisplay(message);
435448
}
436449

437450
dismissCurrentMessage();
@@ -456,7 +469,7 @@ private void dismissCurrentMessage() {
456469
}
457470
}
458471

459-
private void persisIAMessageForRedisplay(final OSInAppMessage message) {
472+
private void persistInAppMessageForRedisplay(final OSInAppMessage message) {
460473
//If the IAM doesn't have the re display configuration then no need to save it
461474
if (!message.getDisplayStats().isRedisplayEnabled())
462475
return;
@@ -474,16 +487,16 @@ public void run() {
474487
}
475488
}, OS_SAVE_IN_APP_MESSAGE).start();
476489

477-
//Update the data to enable future re displays
478-
//Avoid calling the repository data again
479-
int index = displayedMessagesData.indexOf(message);
490+
// Update the data to enable future re displays
491+
// Avoid calling the repository data again
492+
int index = redisplayedInAppMessages.indexOf(message);
480493
if (index != -1) {
481-
displayedMessagesData.set(index, message);
494+
redisplayedInAppMessages.set(index, message);
482495
} else {
483-
displayedMessagesData.add(message);
496+
redisplayedInAppMessages.add(message);
484497
}
485498

486-
OneSignal.onesignalLog(OneSignal.LOG_LEVEL.DEBUG, "persisIAMessageForRedisplay: " + message.toString() + " with msg array data: " + displayedMessagesData.toString());
499+
OneSignal.onesignalLog(OneSignal.LOG_LEVEL.DEBUG, "persistInAppMessageForRedisplay: " + message.toString() + " with msg array data: " + redisplayedInAppMessages.toString());
487500
}
488501

489502
private static @Nullable String htmlPathForMessage(OSInAppMessage message) {
@@ -589,36 +602,36 @@ public void messageTriggerConditionChanged() {
589602
}
590603

591604
/**
592-
* Part of redisplay logic
605+
* Part of redisplay logic
593606
*
594-
* Make all messages with redisplay enable available for redisplay if:
607+
* Make all messages with redisplay available if:
595608
* - Already displayed
596-
* - Trigger changed
597-
* */
598-
private void checkTriggerChanged(Collection<String> newTriggersKeys) {
609+
* - At least one Trigger has changed
610+
*/
611+
private void makeRedisplayMessagesAvailableWithTriggers(Collection<String> newTriggersKeys) {
599612
for (OSInAppMessage message : messages) {
600-
if (displayedMessagesData.contains(message) &&
613+
if (redisplayedInAppMessages.contains(message) &&
601614
triggerController.isTriggerOnMessage(message, newTriggersKeys)) {
602615
message.setTriggerChanged(true);
603616
}
604617
}
605618
}
606619

607620
/**
608-
* Trigger logic
609-
* These methods mostly pass data to the Trigger Controller, but also cause the SDK to
621+
* Trigger logic
622+
* These methods mostly pass data to the Trigger Controller, but also cause the SDK to
610623
* re-evaluate messages to see if we should display a message now that the trigger
611624
* conditions have changed.
612625
*/
613626
void addTriggers(Map<String, Object> newTriggers) {
614627
triggerController.addTriggers(newTriggers);
615-
checkTriggerChanged(newTriggers.keySet());
628+
makeRedisplayMessagesAvailableWithTriggers(newTriggers.keySet());
616629
evaluateInAppMessages();
617630
}
618631

619632
void removeTriggersForKeys(Collection<String> keys) {
620633
triggerController.removeTriggersForKeys(keys);
621-
checkTriggerChanged(keys);
634+
makeRedisplayMessagesAvailableWithTriggers(keys);
622635
evaluateInAppMessages();
623636
}
624637

OneSignalSDK/onesignal/src/main/java/com/onesignal/OSInAppMessageDisplayStats.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -87,14 +87,11 @@ boolean shouldDisplayAgain() {
8787
}
8888

8989
boolean isDelayTimeSatisfied() {
90-
long currentTimeInSeconds = System.currentTimeMillis() / 1000;
91-
9290
if (lastDisplayTime < 0) {
93-
lastDisplayTime = currentTimeInSeconds;
9491
return true;
9592
}
96-
97-
//Calculate gap between display times
93+
long currentTimeInSeconds = System.currentTimeMillis() / 1000;
94+
// Calculate gap between display times
9895
long diffInSeconds = currentTimeInSeconds - lastDisplayTime;
9996
OneSignal.Log(OneSignal.LOG_LEVEL.DEBUG, "OSInAppMessage lastDisplayTime: " + lastDisplayTime +
10097
" currentTimeInSeconds: " + currentTimeInSeconds + " diffInSeconds: " + diffInSeconds + " displayDelay: " + displayDelay);

OneSignalSDK/onesignal/src/main/java/com/onesignal/OSInAppMessageRepository.java

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,32 +15,26 @@
1515

1616
class OSInAppMessageRepository {
1717

18+
// The max time we keep the IAM on the DB
19+
// Currently value: Six months in seconds
20+
private static final long OS_IAM_MAX_CACHE_TIME = 6 * 30 * 24 * 60 * 60;
1821
private final OneSignalDbHelper dbHelper;
1922

2023
OSInAppMessageRepository(OneSignalDbHelper dbHelper) {
2124
this.dbHelper = dbHelper;
2225
}
2326

27+
/**
28+
* Remove IAMs that the last display time was six month ago
29+
*/
2430
@WorkerThread
25-
synchronized void deleteInAppMessage(String messageId) {
31+
synchronized void deleteOldRedisplayedInAppMessages() {
32+
long sixMonthsAgo = System.currentTimeMillis() / 1000 - OS_IAM_MAX_CACHE_TIME;
2633
SQLiteDatabase writableDb = dbHelper.getWritableDbWithRetries();
27-
28-
try {
29-
writableDb.beginTransaction();
30-
writableDb.delete(OneSignalDbContract.InAppMessageTable.TABLE_NAME,
31-
OneSignalDbContract.InAppMessageTable.COLUMN_NAME_MESSAGE_ID + " = ?", new String[]{messageId});
32-
writableDb.setTransactionSuccessful();
33-
} catch (Throwable t) {
34-
OneSignal.Log(OneSignal.LOG_LEVEL.ERROR, "Error deleting in app message! ", t);
35-
} finally {
36-
if (writableDb != null) {
37-
try {
38-
writableDb.endTransaction(); // May throw if transaction was never opened or DB is full.
39-
} catch (Throwable t) {
40-
OneSignal.Log(OneSignal.LOG_LEVEL.ERROR, "Error closing transaction! ", t);
41-
}
42-
}
43-
}
34+
writableDb.delete(OneSignalDbContract.InAppMessageTable.TABLE_NAME,
35+
OneSignalDbContract.InAppMessageTable.COLUMN_NAME_LAST_DISPLAY + "< ?",
36+
new String[]{String.valueOf(sixMonthsAgo)});
37+
writableDb.close();
4438
}
4539

4640
@WorkerThread
@@ -61,7 +55,7 @@ synchronized void saveInAppMessage(OSInAppMessage inAppMessage) {
6155
}
6256

6357
@WorkerThread
64-
synchronized List<OSInAppMessage> getAllInAppMessages() {
58+
synchronized List<OSInAppMessage> getRedisplayedInAppMessages() {
6559
List<OSInAppMessage> iams = new ArrayList<>();
6660
Cursor cursor = null;
6761

OneSignalSDK/unittest/src/test/java/com/onesignal/OneSignalPackagePrivateHelper.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -457,22 +457,22 @@ public static ArrayList<com.onesignal.OSInAppMessage> getInAppMessageDisplayQueu
457457
return com.onesignal.OSInAppMessageController.getController().messageDisplayQueue;
458458
}
459459

460-
public static class OSInAppMessageController extends com.onesignal.OSInAppMessageController {
460+
public static class OSInAppMessageController {
461+
public static final String IN_APP_MESSAGES_JSON_KEY = com.onesignal.OSInAppMessageController.IN_APP_MESSAGES_JSON_KEY;
461462
private static OSInAppMessageController sharedInstance;
462463

463-
OSInAppMessageController(OneSignalDbHelper dbInstance) {
464-
super((dbInstance));
464+
OSInAppMessageController() {
465465
}
466466

467467
public static OSInAppMessageController getController() {
468468
if (sharedInstance == null)
469-
sharedInstance = new OSInAppMessageController(OneSignal.getDBHelperInstance());
469+
sharedInstance = new OSInAppMessageController();
470470

471471
return sharedInstance;
472472
}
473473

474474
public void onMessageActionOccurredOnMessage(@NonNull final com.onesignal.OSInAppMessage message, @NonNull final JSONObject actionJson) {
475-
super.onMessageActionOccurredOnMessage(message, actionJson);
475+
com.onesignal.OSInAppMessageController.getController().onMessageActionOccurredOnMessage(message, actionJson);
476476
}
477477

478478
public void onMessageWasShown(@NonNull com.onesignal.OSInAppMessage message) {

OneSignalSDK/unittest/src/test/java/com/test/onesignal/InAppMessageIntegrationTests.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import java.lang.reflect.Field;
4545
import java.util.ArrayList;
4646
import java.util.HashMap;
47+
import java.util.List;
4748
import java.util.Set;
4849
import java.util.concurrent.Callable;
4950
import java.util.concurrent.TimeUnit;
@@ -76,8 +77,10 @@
7677

7778
@RunWith(RobolectricTestRunner.class)
7879
public class InAppMessageIntegrationTests {
80+
7981
private static final String IAM_CLICK_ID = "button_id_123";
8082
private static final String ONESIGNAL_APP_ID = "b2f7f966-d8cc-11e4-bed1-df8f05be55ba";
83+
private static final long SIX_MONTHS_TIME_SECONDS = 6 * 30 * 24 * 60 * 60;
8184
private static final int LIMIT = 5;
8285
private static final int DELAY = 60;
8386

@@ -849,6 +852,46 @@ public void testInAppMessageMultipleRedisplayReceivesClickId() throws Exception
849852
assertEquals(4, ShadowOneSignalRestClient.requests.size());
850853
}
851854

855+
@Test
856+
public void testInAppMessageRedisplayCacheUpdate() throws Exception {
857+
final long currentTimeInSeconds = System.currentTimeMillis() / 1000;
858+
859+
final OSTestInAppMessage inAppMessage = InAppMessagingHelpers.buildTestMessageWithSingleTriggerAndRedisplay(
860+
OSTriggerKind.CUSTOM,"test_saved", OneSignalPackagePrivateHelper.OSTestTrigger.OSTriggerOperator.EQUAL_TO.toString(), 2, LIMIT, DELAY);
861+
862+
String firstID = inAppMessage.messageId + "_test";
863+
inAppMessage.messageId = firstID;
864+
inAppMessage.getDisplayStats().setLastDisplayTime(currentTimeInSeconds - SIX_MONTHS_TIME_SECONDS + 1);
865+
TestHelpers.saveIAM(inAppMessage);
866+
867+
inAppMessage.getDisplayStats().setLastDisplayTime(currentTimeInSeconds - SIX_MONTHS_TIME_SECONDS - 1);
868+
inAppMessage.messageId += "1";
869+
TestHelpers.saveIAM(inAppMessage);
870+
871+
List<OSTestInAppMessage> savedInAppMessages = TestHelpers.getAllInAppMessages();
872+
873+
assertEquals(2, savedInAppMessages.size());
874+
875+
final OSTestInAppMessage message1 = InAppMessagingHelpers.buildTestMessageWithSingleTriggerAndRedisplay(
876+
OSTriggerKind.CUSTOM,"test_1", OSTestTrigger.OSTriggerOperator.EQUAL_TO.toString(), 2, LIMIT, DELAY);
877+
final OSTestInAppMessage message2 = InAppMessagingHelpers.buildTestMessageWithSingleTriggerAndRedisplay(
878+
OSTriggerKind.CUSTOM,"test_2", OSTestTrigger.OSTriggerOperator.EQUAL_TO.toString(), 2, LIMIT, DELAY);
879+
880+
setMockRegistrationResponseWithMessages(new ArrayList<OSTestInAppMessage>() {{
881+
add(message1);
882+
add(message2);
883+
}});
884+
885+
// Init OneSignal with IAM with redisplay
886+
OneSignalInit();
887+
threadAndTaskWait();
888+
889+
List<OSTestInAppMessage> savedInAppMessagesAfterInit = TestHelpers.getAllInAppMessages();
890+
// Message with old display time should be removed
891+
assertEquals(1, savedInAppMessagesAfterInit.size());
892+
assertEquals(firstID, savedInAppMessagesAfterInit.get(0).messageId);
893+
}
894+
852895
@Test
853896
@Config(sdk = 18)
854897
public void testMessageNotShownForAndroidApi18Lower() throws Exception {

OneSignalSDK/unittest/src/test/java/com/test/onesignal/InAppMessagingUnitTests.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,14 +198,13 @@ public void testBuiltMessageRedisplayLimit() throws JSONException {
198198

199199
@Test
200200
public void testBuiltMessageRedisplayDelay() throws JSONException {
201-
final long currentTimeInSeconds = new Date().getTime() / 1000;
202-
203201
OSTestInAppMessage message = InAppMessagingHelpers.buildTestMessageWitRedisplay(
204202
LIMIT,
205203
DELAY
206204
);
207205

208206
assertTrue(message.getDisplayStats().isDelayTimeSatisfied());
207+
final long currentTimeInSeconds = System.currentTimeMillis() / 1000;
209208

210209
message.getDisplayStats().setLastDisplayTime(currentTimeInSeconds - DELAY);
211210
assertTrue(message.getDisplayStats().isDelayTimeSatisfied());

OneSignalSDK/unittest/src/test/java/com/test/onesignal/MainOneSignalClassRunner.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,6 @@ public static void afterEverything() throws Exception {
247247
cleanUp();
248248
}
249249

250-
251250
@Test
252251
public void testInitFromApplicationContext() throws Exception {
253252
// Application.onCreate

0 commit comments

Comments
 (0)