diff --git a/CHANGELOG.md b/CHANGELOG.md index 632930094..5244459a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - `Custom(layoutRes)` — inflates the integrator's own toolbar layout. Views tagged with the reserved ids `@id/iterable_reserved_inbox_toolbar_action` and `@id/iterable_reserved_inbox_toolbar_title` are auto-wired to the SDK's back handler and title binding respectively. Both ids are optional. - Configure programmatically via `IterableInboxFragment.newInstance(...)` (new 2-arg and 6-arg overloads) or via `IterableInboxActivity` intent extras (`TOOLBAR_OPTION` / `TOOLBAR_TITLE`). - Requires the host activity to use a `Theme.AppCompat` descendant when the toolbar is enabled. +- Added `appAlreadyRunning` field to `trackPushOpen`. New `trackPushOpen(int, int, String, boolean, JSONObject)` overload sends the value through; existing overloads default to `false`. ### Fixed - Fixed a `TransactionTooLargeException` crash when displaying in-app messages with oversized HTML payloads. The HTML is no longer serialized into the fragment's saved instance state; it is reloaded from storage on recreation. In-apps with missing HTML now dismiss gracefully without registering tracking events, and a warning is logged for HTML payloads exceeding the recommended size. diff --git a/iterableapi/src/main/java/com/iterable/iterableapi/IterableApi.java b/iterableapi/src/main/java/com/iterable/iterableapi/IterableApi.java index 3f45cafaa..a49ab8286 100644 --- a/iterableapi/src/main/java/com/iterable/iterableapi/IterableApi.java +++ b/iterableapi/src/main/java/com/iterable/iterableapi/IterableApi.java @@ -1274,7 +1274,7 @@ public void registerDeviceToken(@NonNull String deviceToken) { } public void trackPushOpen(int campaignId, int templateId, @NonNull String messageId) { - queueOrExecute(() -> trackPushOpen(campaignId, templateId, messageId, null), "trackPushOpen(" + campaignId + ", " + templateId + ", " + maskPII(messageId) + ")"); + trackPushOpen(campaignId, templateId, messageId, false, null); } /** @@ -1283,14 +1283,26 @@ public void trackPushOpen(int campaignId, int templateId, @NonNull String messag * @param templateId */ public void trackPushOpen(int campaignId, int templateId, @NonNull String messageId, @Nullable JSONObject dataFields) { + trackPushOpen(campaignId, templateId, messageId, false, dataFields); + } + + /** + * Tracks when a push notification is opened on device. + * @param campaignId + * @param templateId + * @param messageId + * @param appAlreadyRunning Whether the app was already running when the push was received. + * @param dataFields + */ + public void trackPushOpen(int campaignId, int templateId, @NonNull String messageId, boolean appAlreadyRunning, @Nullable JSONObject dataFields) { queueOrExecute(() -> { if (messageId == null) { IterableLogger.e(TAG, "messageId is null"); return; } - apiClient.trackPushOpen(campaignId, templateId, messageId, dataFields); - }, "trackPushOpen(" + campaignId + ", " + templateId + ", " + maskPII(messageId) + ", dataFields)"); + apiClient.trackPushOpen(campaignId, templateId, messageId, appAlreadyRunning, dataFields); + }, "trackPushOpen(" + campaignId + ", " + templateId + ", " + maskPII(messageId) + ", " + appAlreadyRunning + ", dataFields)"); } /** diff --git a/iterableapi/src/main/java/com/iterable/iterableapi/IterableApiClient.java b/iterableapi/src/main/java/com/iterable/iterableapi/IterableApiClient.java index 924ebc24e..e8e685b5e 100644 --- a/iterableapi/src/main/java/com/iterable/iterableapi/IterableApiClient.java +++ b/iterableapi/src/main/java/com/iterable/iterableapi/IterableApiClient.java @@ -587,13 +587,14 @@ public void trackEmbeddedSession(@NonNull IterableEmbeddedSession session) { } } - protected void trackPushOpen(int campaignId, int templateId, @NonNull String messageId, @Nullable JSONObject dataFields) { + protected void trackPushOpen(int campaignId, int templateId, @NonNull String messageId, boolean appAlreadyRunning, @Nullable JSONObject dataFields) { JSONObject requestJSON = new JSONObject(); try { if (dataFields == null) { dataFields = new JSONObject(); } + dataFields.put(IterableConstants.KEY_APP_ALREADY_RUNNING, appAlreadyRunning); addEmailOrUserIdToJson(requestJSON); requestJSON.put(IterableConstants.KEY_CAMPAIGN_ID, campaignId); diff --git a/iterableapi/src/main/java/com/iterable/iterableapi/IterableConstants.java b/iterableapi/src/main/java/com/iterable/iterableapi/IterableConstants.java index eb2d3fc4d..c3ac914a4 100644 --- a/iterableapi/src/main/java/com/iterable/iterableapi/IterableConstants.java +++ b/iterableapi/src/main/java/com/iterable/iterableapi/IterableConstants.java @@ -22,6 +22,7 @@ public final class IterableConstants { public static final String HEADER_SDK_AUTHORIZATION = "Authorization"; public static final String HEADER_SDK_AUTH_FORMAT = "Bearer "; public static final String HEADER_SDK_PROCESSOR_TYPE = "SDK-Request-Processor"; + public static final String KEY_APP_ALREADY_RUNNING = "appAlreadyRunning"; public static final String KEY_APPLICATION_NAME = "applicationName"; public static final String KEY_CAMPAIGN_ID = "campaignId"; public static final String KEY_CURRENT_EMAIL = "currentEmail"; diff --git a/iterableapi/src/test/java/com/iterable/iterableapi/IterableApiTest.java b/iterableapi/src/test/java/com/iterable/iterableapi/IterableApiTest.java index 04303edd8..a8ee54116 100644 --- a/iterableapi/src/test/java/com/iterable/iterableapi/IterableApiTest.java +++ b/iterableapi/src/test/java/com/iterable/iterableapi/IterableApiTest.java @@ -499,6 +499,43 @@ public void testInAppOpen() throws Exception { assertEquals("testMessageId", requestJson.getString(IterableConstants.KEY_MESSAGE_ID)); } + @Test + public void testTrackPushOpenDefaultsAppAlreadyRunningToFalse() throws Exception { + server.enqueue(new MockResponse().setResponseCode(200).setBody("{}")); + + IterableApi.initialize(getContext(), "apiKey", new IterableConfig.Builder().setAutoPushRegistration(false).build()); + IterableApi.getInstance().setEmail("test@email.com"); + IterableApi.getInstance().trackPushOpen(1234, 4321, "testMessageId"); + shadowOf(getMainLooper()).idle(); + + RecordedRequest trackPushOpenRequest = server.takeRequest(1, TimeUnit.SECONDS); + assertNotNull(trackPushOpenRequest); + assertEquals("/" + IterableConstants.ENDPOINT_TRACK_PUSH_OPEN, trackPushOpenRequest.getPath()); + JSONObject requestJson = new JSONObject(trackPushOpenRequest.getBody().readUtf8()); + assertEquals(1234, requestJson.getInt(IterableConstants.KEY_CAMPAIGN_ID)); + assertEquals(4321, requestJson.getInt(IterableConstants.KEY_TEMPLATE_ID)); + assertEquals("testMessageId", requestJson.getString(IterableConstants.KEY_MESSAGE_ID)); + assertEquals(false, requestJson.getJSONObject(IterableConstants.KEY_DATA_FIELDS).getBoolean(IterableConstants.KEY_APP_ALREADY_RUNNING)); + } + + @Test + public void testTrackPushOpenSendsAppAlreadyRunningAndPreservesDataFields() throws Exception { + server.enqueue(new MockResponse().setResponseCode(200).setBody("{}")); + + IterableApi.initialize(getContext(), "apiKey", new IterableConfig.Builder().setAutoPushRegistration(false).build()); + IterableApi.getInstance().setEmail("test@email.com"); + IterableApi.getInstance().trackPushOpen(1234, 4321, "testMessageId", true, new JSONObject("{\"key\": \"value\"}")); + shadowOf(getMainLooper()).idle(); + + RecordedRequest trackPushOpenRequest = server.takeRequest(1, TimeUnit.SECONDS); + assertNotNull(trackPushOpenRequest); + assertEquals("/" + IterableConstants.ENDPOINT_TRACK_PUSH_OPEN, trackPushOpenRequest.getPath()); + JSONObject requestJson = new JSONObject(trackPushOpenRequest.getBody().readUtf8()); + JSONObject dataFields = requestJson.getJSONObject(IterableConstants.KEY_DATA_FIELDS); + assertEquals(true, dataFields.getBoolean(IterableConstants.KEY_APP_ALREADY_RUNNING)); + assertEquals("value", dataFields.getString("key")); + } + @Test public void testInAppOpenExtended() throws Exception { server.enqueue(new MockResponse().setResponseCode(200).setBody("{}"));