Skip to content

Commit 09ebc87

Browse files
authored
Merge pull request #1239 from OneSignal/feature/iam_carousel
Iam carousel page impressions
2 parents be9f2fa + 38ef376 commit 09ebc87

File tree

8 files changed

+167
-5
lines changed

8 files changed

+167
-5
lines changed

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public class OSInAppMessageAction {
1717
private static final String ID = "id";
1818
private static final String NAME = "name";
1919
private static final String URL = "url";
20+
private static final String PAGE_ID = "pageId";
2021
private static final String URL_TARGET = "url_target";
2122
private static final String CLOSE = "close";
2223
private static final String CLICK_NAME = "click_name";
@@ -52,6 +53,12 @@ public class OSInAppMessageAction {
5253
@Nullable
5354
private String clickUrl;
5455

56+
/**
57+
* UUID for the page in an IAM Carousel
58+
*/
59+
@Nullable
60+
private String pageId;
61+
5562
/**
5663
* Outcome for action
5764
*/
@@ -83,6 +90,7 @@ public class OSInAppMessageAction {
8390
clickId = json.optString(ID, null);
8491
clickName = json.optString(NAME, null);
8592
clickUrl = json.optString(URL, null);
93+
pageId = json.optString(PAGE_ID, null);
8694
urlTarget = OSInAppMessageActionUrlType.fromString(json.optString(URL_TARGET, null));
8795
if (urlTarget == null)
8896
urlTarget = OSInAppMessageActionUrlType.IN_APP_WEBVIEW;
@@ -125,6 +133,10 @@ public String getClickName() {
125133
return clickName;
126134
}
127135

136+
String getPageId() {
137+
return pageId;
138+
}
139+
128140
@Nullable
129141
public OSInAppMessageActionUrlType getUrlTarget() {
130142
return urlTarget;

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

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ class OSInAppMessageController implements OSDynamicTriggerControllerObserver, OS
5151
// This means their impression has been successfully posted to our backend and should not be counted again
5252
@NonNull
5353
final private Set<String> impressionedMessages;
54+
// This means their impression has been successfully posted to our backend and should not be counted again
55+
@NonNull
56+
final private Set<String> viewedPageIds;
5457
// IAM clicks that have been successfully posted to our backend and should not be counted again
5558
@NonNull
5659
final private Set<String> clickedClickIds;
@@ -75,6 +78,7 @@ protected OSInAppMessageController(OneSignalDbHelper dbHelper, OSLogger logger)
7578
dismissedMessages = OSUtils.newConcurrentSet();
7679
messageDisplayQueue = new ArrayList<>();
7780
impressionedMessages = OSUtils.newConcurrentSet();
81+
viewedPageIds = OSUtils.newConcurrentSet();
7882
clickedClickIds = OSUtils.newConcurrentSet();
7983
triggerController = new OSTriggerController(this);
8084
systemConditionController = new OSSystemConditionController(this);
@@ -96,6 +100,14 @@ protected OSInAppMessageController(OneSignalDbHelper dbHelper, OSLogger logger)
96100
if (tempImpressionsSet != null)
97101
impressionedMessages.addAll(tempImpressionsSet);
98102

103+
Set<String> tempPageImpressionsSet = OneSignalPrefs.getStringSet(
104+
OneSignalPrefs.PREFS_ONESIGNAL,
105+
OneSignalPrefs.PREFS_OS_PAGE_IMPRESSIONED_IAMS,
106+
null
107+
);
108+
if (tempPageImpressionsSet != null)
109+
viewedPageIds.addAll(tempPageImpressionsSet);
110+
99111
Set<String> tempClickedMessageIdsSet = OneSignalPrefs.getStringSet(
100112
OneSignalPrefs.PREFS_ONESIGNAL,
101113
OneSignalPrefs.PREFS_OS_CLICKED_CLICK_IDS_IAMS,
@@ -281,6 +293,14 @@ void onFailure(int statusCode, String response, Throwable throwable) {
281293
}
282294
}
283295

296+
void onPageChanged(@NonNull final OSInAppMessage message, @NonNull final JSONObject eventJson) {
297+
final OSInAppMessagePage newPage = new OSInAppMessagePage(eventJson);
298+
if (message.isPreview) {
299+
return;
300+
}
301+
fireRESTCallForPageChange(message, newPage);
302+
}
303+
284304
void onMessageActionOccurredOnMessage(@NonNull final OSInAppMessage message, @NonNull final JSONObject actionJson) throws JSONException {
285305
final OSInAppMessageAction action = new OSInAppMessageAction(actionJson);
286306
action.setFirstClick(message.takeActionAsUnique());
@@ -409,6 +429,60 @@ else if (action.getUrlTarget() == OSInAppMessageAction.OSInAppMessageActionUrlTy
409429
}
410430
}
411431

432+
private void saveViewedPageIdsToPrefs() {
433+
OneSignalPrefs.saveStringSet(
434+
OneSignalPrefs.PREFS_ONESIGNAL,
435+
OneSignalPrefs.PREFS_OS_PAGE_IMPRESSIONED_IAMS,
436+
// Post success, store impressioned pages to disk
437+
viewedPageIds);
438+
}
439+
440+
private void fireRESTCallForPageChange(@NonNull final OSInAppMessage message, @NonNull final OSInAppMessagePage page) {
441+
final String variantId = variantIdForMessage(message);
442+
if (variantId == null)
443+
return;
444+
445+
final String pageId = page.getPageId();
446+
447+
final String messagePrefixedPageId = message.messageId + pageId;
448+
449+
// Never send multiple page impressions for the same message UUID unless that page change is from an IAM with redisplay
450+
if (viewedPageIds.contains(messagePrefixedPageId)) {
451+
OneSignal.onesignalLog(OneSignal.LOG_LEVEL.VERBOSE, "Already sent page impression for id: " + pageId);
452+
return;
453+
}
454+
455+
viewedPageIds.add(messagePrefixedPageId);
456+
457+
try {
458+
JSONObject json = new JSONObject() {{
459+
put("app_id", OneSignal.appId);
460+
put("player_id", OneSignal.getUserId());
461+
put("variant_id", variantId);
462+
put("device_type", new OSUtils().getDeviceType());
463+
put("page_id", pageId);
464+
}};
465+
466+
OneSignalRestClient.post("in_app_messages/" + message.messageId + "/pageImpression", json, new ResponseHandler() {
467+
@Override
468+
void onSuccess(String response) {
469+
printHttpSuccessForInAppMessageRequest("page impression", response);
470+
saveViewedPageIdsToPrefs();
471+
}
472+
473+
@Override
474+
void onFailure(int statusCode, String response, Throwable throwable) {
475+
printHttpErrorForInAppMessageRequest("page impression", statusCode, response);
476+
// Post failed, viewed page should be removed and this way another post can be attempted
477+
viewedPageIds.remove(messagePrefixedPageId);
478+
}
479+
});
480+
} catch (JSONException e) {
481+
e.printStackTrace();
482+
OneSignal.onesignalLog(OneSignal.LOG_LEVEL.ERROR, "Unable to execute in-app message impression HTTP request due to invalid JSON");
483+
}
484+
}
485+
412486
private void fireRESTCallForClick(@NonNull final OSInAppMessage message, @NonNull final OSInAppMessageAction action) {
413487
final String variantId = variantIdForMessage(message);
414488
if (variantId == null)
@@ -493,6 +567,10 @@ private void setDataForRedisplay(OSInAppMessage message) {
493567

494568
dismissedMessages.remove(message.messageId);
495569
impressionedMessages.remove(message.messageId);
570+
// Pages from different IAMs should not impact each other so we can clear the entire
571+
// list when an IAM is dismissed or we are re-displaying the same one
572+
viewedPageIds.clear();
573+
saveViewedPageIdsToPrefs();
496574
message.clearClickIds();
497575
}
498576
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.onesignal
2+
3+
4+
import org.json.JSONException
5+
import org.json.JSONObject
6+
7+
const val PAGE_ID = "pageId"
8+
const val PAGE_INDEX = "pageIndex"
9+
10+
class OSInAppMessagePage constructor(jsonObject: JSONObject) {
11+
var pageId: String? = null
12+
var pageIndex: String? = null
13+
14+
init {
15+
pageId = jsonObject.optString(PAGE_ID, null)
16+
pageIndex = jsonObject.optString(PAGE_INDEX, null)
17+
}
18+
19+
fun toJSONObject(): JSONObject {
20+
val mainObj = JSONObject()
21+
try {
22+
mainObj.put(PAGE_ID, pageId)
23+
mainObj.put(PAGE_INDEX, pageIndex)
24+
} catch (e: JSONException) {
25+
e.printStackTrace()
26+
}
27+
return mainObj
28+
}
29+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ class OneSignalPrefs {
108108
public static final String PREFS_OS_DISMISSED_IAMS = "PREFS_OS_DISPLAYED_IAMS";
109109
public static final String PREFS_OS_IMPRESSIONED_IAMS = "PREFS_OS_IMPRESSIONED_IAMS";
110110
public static final String PREFS_OS_CLICKED_CLICK_IDS_IAMS = "PREFS_OS_CLICKED_CLICK_IDS_IAMS";
111+
public static final String PREFS_OS_PAGE_IMPRESSIONED_IAMS = "PREFS_OS_PAGE_IMPRESSIONED_IAMS";
111112

112113
// Player Purchase Keys
113114
static final String PREFS_PURCHASE_TOKENS = "purchaseTokens";

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

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ class OSJavaScriptInterface {
155155
static final String EVENT_TYPE_KEY = "type";
156156
static final String EVENT_TYPE_RENDERING_COMPLETE = "rendering_complete";
157157
static final String EVENT_TYPE_ACTION_TAKEN = "action_taken";
158+
static final String EVENT_TYPE_PAGE_CHANGE = "page_change";
158159

159160
static final String IAM_DISPLAY_LOCATION_KEY = "displayLocation";
160161
static final String IAM_PAGE_META_DATA_KEY = "pageMetaData";
@@ -168,11 +169,20 @@ public void postMessage(String message) {
168169
JSONObject jsonObject = new JSONObject(message);
169170
String messageType = jsonObject.getString(EVENT_TYPE_KEY);
170171

171-
if (messageType.equals(EVENT_TYPE_RENDERING_COMPLETE))
172-
handleRenderComplete(jsonObject);
173-
else if (messageType.equals(EVENT_TYPE_ACTION_TAKEN) && !messageView.isDragging()) {
174-
// Added handling so that click actions won't trigger while dragging the IAM
175-
handleActionTaken(jsonObject);
172+
switch (messageType) {
173+
case EVENT_TYPE_RENDERING_COMPLETE:
174+
handleRenderComplete(jsonObject);
175+
break;
176+
case EVENT_TYPE_ACTION_TAKEN:
177+
// Added handling so that click actions won't trigger while dragging the IAM
178+
if (!messageView.isDragging())
179+
handleActionTaken(jsonObject);
180+
break;
181+
case EVENT_TYPE_PAGE_CHANGE:
182+
handlePageChange(jsonObject);
183+
break;
184+
default:
185+
break;
176186
}
177187
} catch (JSONException e) {
178188
e.printStackTrace();
@@ -226,6 +236,10 @@ private void handleActionTaken(JSONObject jsonObject) throws JSONException {
226236
if (close)
227237
dismissAndAwaitNextMessage(null);
228238
}
239+
240+
private void handlePageChange(JSONObject jsonObject) throws JSONException {
241+
OneSignal.getInAppMessageController().onPageChanged(message, jsonObject);
242+
}
229243
}
230244

231245
private static int pageRectToViewHeight(final @NonNull Activity activity, @NonNull JSONObject jsonObject) {

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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public class InAppMessagingHelpers {
1717
public static final String TEST_ENGLISH_ANDROID_VARIANT_ID = "11e4-bed1-df8f05be55ba-a4b3gj7f-d8cc";
1818
public static final String ONESIGNAL_APP_ID = "b4f7f966-d8cc-11e4-bed1-df8f05be55ba";
1919
public static final String IAM_CLICK_ID = "12345678-1234-1234-1234-123456789012";
20+
public static final String IAM_PAGE_ID = "12345678-1234-ABCD-1234-123456789012";
2021

2122
public static boolean evaluateMessage(OSInAppMessage message) {
2223
return OneSignal.getInAppMessageController().triggerController.evaluateMessageTriggers(message);
@@ -171,9 +172,17 @@ public static JSONObject buildTestActionJson() throws JSONException {
171172
put("url", "https://www.onesignal.com");
172173
put("url_target", "webview");
173174
put("close", true);
175+
put("pageId", IAM_PAGE_ID);
174176
put("data", new JSONObject() {{
175177
put("test", "value");
176178
}});
177179
}};
178180
}
181+
182+
public static JSONObject buildTestPageJson() throws JSONException {
183+
return new JSONObject() {{
184+
put("pageIndex", 1);
185+
put("pageId", IAM_PAGE_ID);
186+
}};
187+
}
179188
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,10 @@ public static void onMessageWasShown(@NonNull com.onesignal.OSInAppMessage messa
495495
OneSignal.getInAppMessageController().onMessageWasShown(message);
496496
}
497497

498+
public static void onPageChanged(@NonNull com.onesignal.OSInAppMessage message, @NonNull final JSONObject eventJson) {
499+
OneSignal.getInAppMessageController().onPageChanged(message, eventJson);
500+
}
501+
498502
public static List<OSTestInAppMessage> getRedisplayInAppMessages() {
499503
List<OSInAppMessage> messages = OneSignal.getInAppMessageController().getRedisplayedInAppMessages();
500504
List<OSTestInAppMessage> testMessages = new ArrayList<>();

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -616,4 +616,19 @@ public void testOnMessageWasShown() throws Exception {
616616
assertEquals(1, iamImpressionRequest.payload.get("device_type"));
617617
assertEquals(true, iamImpressionRequest.payload.get("first_impression"));
618618
}
619+
620+
@Test
621+
public void testOnPageChanged() throws Exception {
622+
threadAndTaskWait();
623+
624+
OneSignalPackagePrivateHelper.onPageChanged(message, InAppMessagingHelpers.buildTestPageJson());
625+
626+
ShadowOneSignalRestClient.Request iamPageImpressionRequest = ShadowOneSignalRestClient.requests.get(2);
627+
628+
assertEquals("in_app_messages/" + message.messageId + "/pageImpression", iamPageImpressionRequest.url);
629+
assertEquals(InAppMessagingHelpers.ONESIGNAL_APP_ID, iamPageImpressionRequest.payload.get("app_id"));
630+
assertEquals(ShadowOneSignalRestClient.pushUserId, iamPageImpressionRequest.payload.get("player_id"));
631+
assertEquals(1, iamPageImpressionRequest.payload.get("device_type"));
632+
assertEquals(InAppMessagingHelpers.IAM_PAGE_ID, iamPageImpressionRequest.payload.get("page_id"));
633+
}
619634
}

0 commit comments

Comments
 (0)