diff --git a/src/main/java/com/clevertap/apns/Notification.java b/src/main/java/com/clevertap/apns/Notification.java index 1c71be6..9f454a7 100644 --- a/src/main/java/com/clevertap/apns/Notification.java +++ b/src/main/java/com/clevertap/apns/Notification.java @@ -37,6 +37,7 @@ import java.io.UnsupportedEncodingException; import java.util.HashMap; +import java.util.Map; import java.util.UUID; /** @@ -303,6 +304,169 @@ public Builder interruptionLevel(InterruptionLevel interruptionLevel) { return this; } + // sound dictionary support + @SuppressWarnings("unchecked") + private HashMap getOrCreateSoundMap() { + Object existing = aps.get("sound"); + if (existing instanceof HashMap) { + return (HashMap) existing; + } + return new HashMap<>(); + } + + public Builder sound(Map soundDict) { + if (soundDict != null) { + aps.put("sound", soundDict); + } else { + aps.remove("sound"); + } + return this; + } + + public Builder soundCritical(int critical) { + HashMap map = getOrCreateSoundMap(); + map.put("critical", critical); + aps.put("sound", map); + return this; + } + + public Builder soundName(String name) { + HashMap map = getOrCreateSoundMap(); + if (name != null) { + map.put("name", name); + } else { + map.remove("name"); + } + aps.put("sound", map); + return this; + } + + public Builder soundVolume(double volume) { + HashMap map = getOrCreateSoundMap(); + map.put("volume", volume); + aps.put("sound", map); + return this; + } + + // alert dictionary keys + public Builder subtitle(String subtitle) { + alert.put("subtitle", subtitle); + return this; + } + + public Builder launchImage(String launchImage) { + alert.put("launch-image", launchImage); + return this; + } + + public Builder titleLocKey(String key) { + alert.put("title-loc-key", key); + return this; + } + + public Builder titleLocArgs(String[] args) { + alert.put("title-loc-args", args); + return this; + } + + public Builder subtitleLocKey(String key) { + alert.put("subtitle-loc-key", key); + return this; + } + + public Builder subtitleLocArgs(String[] args) { + alert.put("subtitle-loc-args", args); + return this; + } + + public Builder locKey(String key) { + alert.put("loc-key", key); + return this; + } + + public Builder locArgs(String[] args) { + alert.put("loc-args", args); + return this; + } + + // additional APS headers + public Builder threadId(String threadId) { + if (threadId != null) { + aps.put("thread-id", threadId); + } else { + aps.remove("thread-id"); + } + return this; + } + + public Builder targetContentId(String id) { + if (id != null) { + aps.put("target-content-id", id); + } else { + aps.remove("target-content-id"); + } + return this; + } + + public Builder filterCriteria(String criteria) { + if (criteria != null) { + aps.put("filter-criteria", criteria); + } else { + aps.remove("filter-criteria"); + } + return this; + } + + public Builder staleDate(long date) { + aps.put("stale-date", date); + return this; + } + + public Builder contentState(Map state) { + if (state != null) { + aps.put("content-state", state); + } else { + aps.remove("content-state"); + } + return this; + } + + public Builder timestamp(long ts) { + aps.put("timestamp", ts); + return this; + } + + public Builder event(String event) { + if (event != null) { + aps.put("event", event); + } else { + aps.remove("event"); + } + return this; + } + + public Builder dismissalDate(long date) { + aps.put("dismissal-date", date); + return this; + } + + public Builder attributesType(String type) { + if (type != null) { + aps.put("attributes-type", type); + } else { + aps.remove("attributes-type"); + } + return this; + } + + public Builder attributes(Map attrs) { + if (attrs != null) { + aps.put("attributes", attrs); + } else { + aps.remove("attributes"); + } + return this; + } public int size() { try { diff --git a/src/test/java/com/clevertap/apns/NotificationTest.java b/src/test/java/com/clevertap/apns/NotificationTest.java index 16b37a9..e3ef092 100644 --- a/src/test/java/com/clevertap/apns/NotificationTest.java +++ b/src/test/java/com/clevertap/apns/NotificationTest.java @@ -6,6 +6,8 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import java.util.HashMap; +import java.util.Map; import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.*; @@ -104,4 +106,53 @@ void resetInterruptionLevel() { assertEquals("{\"aps\":{\"alert\":{}}}", notification2.getPayload()); } + @Test + void testThreadId() { + Notification notification = new Notification.Builder("token") + .threadId("tid123") + .build(); + String payload = notification.getPayload(); + assertTrue(payload.contains("\"thread-id\":\"tid123\"")); + assertTrue(payload.contains("\"alert\":{}")); + } + + @Test + void testStaleDate() { + Notification notification = new Notification.Builder("token") + .staleDate(987654321L) + .build(); + String payload = notification.getPayload(); + assertTrue(payload.contains("\"stale-date\":987654321")); + assertTrue(payload.contains("\"alert\":{}")); + } + + @Test + void testSoundDictionary() { + Map soundDict = new HashMap<>(); + soundDict.put("name", "my_sound"); + soundDict.put("critical", 2); + Notification notification = new Notification.Builder("token") + .sound(soundDict) + .build(); + String payload = notification.getPayload(); + assertTrue(payload.contains("\"sound\":{")); + assertTrue(payload.contains("\"name\":\"my_sound\"")); + assertTrue(payload.contains("\"critical\":2")); + } + + @Test + void testAlertLocalization() { + Notification notification = new Notification.Builder("token") + .titleLocKey("LOC_KEY") + .titleLocArgs(new String[]{"arg1","arg2"}) + .subtitleLocKey("SUB_KEY") + .subtitleLocArgs(new String[]{"sub1","sub2"}) + .build(); + String payload = notification.getPayload(); + assertTrue(payload.contains("\"title-loc-key\":\"LOC_KEY\"")); + assertTrue(payload.contains("\"title-loc-args\":[\"arg1\",\"arg2\"]")); + assertTrue(payload.contains("\"subtitle-loc-key\":\"SUB_KEY\"")); + assertTrue(payload.contains("\"subtitle-loc-args\":[\"sub1\",\"sub2\"]")); + } + } \ No newline at end of file