Skip to content

Commit 3d2b5b0

Browse files
authored
Merge pull request #1695 from OneSignal/user-model/notification-clicked
[User Model] Notification Clicked Handler
2 parents 67f40a9 + 7c6d8be commit 3d2b5b0

32 files changed

+233
-368
lines changed

Examples/OneSignalDemo/app/src/main/java/com/onesignal/sdktest/application/MainApplication.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,16 @@
99

1010
import com.onesignal.OneSignal;
1111
import com.onesignal.inAppMessages.IInAppMessage;
12-
import com.onesignal.inAppMessages.IInAppMessageAction;
1312
import com.onesignal.inAppMessages.IInAppMessageClickHandler;
13+
import com.onesignal.inAppMessages.IInAppMessageClickResult;
1414
import com.onesignal.inAppMessages.IInAppMessageLifecycleHandler;
1515
import com.onesignal.debug.LogLevel;
1616
import com.onesignal.notifications.INotification;
1717
import com.onesignal.sdktest.BuildConfig;
1818
import com.onesignal.sdktest.R;
1919
import com.onesignal.sdktest.constant.Tag;
2020
import com.onesignal.sdktest.constant.Text;
21+
import com.onesignal.sdktest.notification.OneSignalNotificationSender;
2122
import com.onesignal.sdktest.util.SharedPreferenceUtil;
2223

2324
import org.json.JSONObject;
@@ -43,6 +44,7 @@ public void onCreate() {
4344
SharedPreferenceUtil.cacheOneSignalAppId(this, appId);
4445
}
4546

47+
OneSignalNotificationSender.setAppId(appId);
4648
OneSignal.initWithContext(this, appId);
4749

4850
OneSignal.getInAppMessages().setInAppMessageLifecycleHandler(new IInAppMessageLifecycleHandler() {
@@ -69,12 +71,12 @@ public void onDidDismissInAppMessage(@NonNull IInAppMessage message) {
6971

7072
OneSignal.getInAppMessages().setInAppMessageClickHandler(new IInAppMessageClickHandler() {
7173
@Override
72-
public void inAppMessageClicked(@Nullable IInAppMessageAction result) {
74+
public void inAppMessageClicked(@Nullable IInAppMessageClickResult result) {
7375
Log.v("MainApplication", "inAppMessageClicked");
7476
}
7577
});
7678

77-
OneSignal.getNotifications().setNotificationOpenedHandler(result ->
79+
OneSignal.getNotifications().setNotificationClickHandler(result ->
7880
{
7981
Log.v("MainApplication", "INotificationOpenedResult: " + result);
8082
});
Lines changed: 57 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,36 @@
11
package com.onesignal.sdktest.notification;
22

3+
import android.os.Build;
34
import android.util.Log;
45

5-
import com.onesignal.Continue;
66
import com.onesignal.OneSignal;
77
import com.onesignal.user.subscriptions.IPushSubscription;
88
import com.onesignal.sdktest.constant.Tag;
99
import com.onesignal.sdktest.type.Notification;
1010

11-
import org.json.JSONException;
1211
import org.json.JSONObject;
1312

13+
import java.io.InputStream;
14+
import java.net.HttpURLConnection;
15+
import java.net.URL;
16+
import java.nio.charset.StandardCharsets;
17+
import java.util.Scanner;
18+
1419
public class OneSignalNotificationSender {
1520

21+
public static void setAppId(String appId) {
22+
_appId = appId;
23+
}
24+
private static String _appId = "";
25+
26+
/**
27+
* Send a notification to this device through the OneSignal Platform. Note this form of the
28+
* API should not be used in a production setting as it is not safe. Rather, the device should
29+
* make an API call to it's own backend, which should handle the API call to OneSignal (where it
30+
* can safely provide the application API Key).
31+
*
32+
* @param notification The notification that is to be sent.
33+
*/
1634
public static void sendDeviceNotification(final Notification notification) {
1735
new Thread(() -> {
1836
IPushSubscription subscription = OneSignal.getUser().getSubscriptions().getPush();
@@ -22,7 +40,7 @@ public static void sendDeviceNotification(final Notification notification) {
2240

2341
int pos = notification.getTemplatePos();
2442
try {
25-
JSONObject notificationContent = new JSONObject("{'include_player_ids': ['" + subscription.getId() + "']," +
43+
JSONObject notificationContent = new JSONObject("{'app_id': '" + _appId + "', 'include_player_ids': ['" + subscription.getId() + "']," +
2644
"'headings': {'en': '" + notification.getTitle(pos) + "'}," +
2745
"'contents': {'en': '" + notification.getMessage(pos) + "'}," +
2846
"'small_icon': '" + notification.getSmallIconRes() + "'," +
@@ -34,20 +52,46 @@ public static void sendDeviceNotification(final Notification notification) {
3452
"'android_accent_color': 'FFE9444E'," +
3553
"'android_sound': 'nil'}");
3654

37-
OneSignal.getNotifications().postNotification(notificationContent, Continue.with(r -> {
38-
if(r.isSuccess())
39-
{
40-
Log.d(Tag.DEBUG, "Success sending notification: " + r.getData().toString());
55+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
56+
HttpURLConnection con = (HttpURLConnection) new URL("https://onesignal.com/api/v1/notifications").openConnection();
57+
58+
con.setUseCaches(false);
59+
con.setConnectTimeout(30000);
60+
con.setReadTimeout(30000);
61+
con.setRequestProperty("Accept", "application/vnd.onesignal.v1+json");
62+
con.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
63+
con.setRequestMethod("POST");
64+
con.setDoOutput(true);
65+
con.setDoInput(true);
66+
67+
byte[] outputBytes = notificationContent.toString().getBytes(StandardCharsets.UTF_8);
68+
con.setFixedLengthStreamingMode(outputBytes.length);
69+
con.getOutputStream().write(outputBytes);
70+
71+
int httpResponse = con.getResponseCode();
72+
73+
if(httpResponse == HttpURLConnection.HTTP_ACCEPTED || httpResponse == HttpURLConnection.HTTP_OK) {
74+
InputStream inputStream = con.getInputStream();
75+
Scanner scanner = new Scanner(inputStream, "UTF-8");
76+
String responseStr = "";
77+
if (scanner.useDelimiter("\\A").hasNext())
78+
responseStr = scanner.next();
79+
scanner.close();
80+
Log.d(Tag.DEBUG, "Success sending notification: " + responseStr);
4181
}
42-
else if(r.getThrowable() != null)
43-
{
44-
Log.d(Tag.ERROR, "Failure sending notification: ", r.getThrowable());
82+
else {
83+
InputStream inputStream = con.getErrorStream();
84+
Scanner scanner = new Scanner(inputStream, "UTF-8");
85+
String responseStr = "";
86+
if (scanner.useDelimiter("\\A").hasNext())
87+
responseStr = scanner.next();
88+
scanner.close();
89+
Log.d(Tag.ERROR, "Failure sending notification: " + responseStr);
4590
}
46-
}));
47-
} catch (JSONException e) {
91+
}
92+
} catch (Exception e) {
4893
e.printStackTrace();
4994
}
5095
}).start();
5196
}
52-
5397
}

OneSignalSDK/onesignal/inAppMessages/src/main/java/com/onesignal/inAppMessages/internal/DummyInAppMessagesManager.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ internal class DummyInAppMessagesManager : IInAppMessagesManager {
2121
override fun clearTriggers() {
2222
}
2323

24-
override fun setInAppMessageLifecycleHandler(handler: IInAppMessageLifecycleHandler) {
24+
override fun setInAppMessageLifecycleHandler(handler: IInAppMessageLifecycleHandler?) {
2525
}
2626

27-
override fun setInAppMessageClickHandler(handler: IInAppMessageClickHandler) {
27+
override fun setInAppMessageClickHandler(handler: IInAppMessageClickHandler?) {
2828
}
2929
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.onesignal.inAppMessages.internal
2+
3+
import com.onesignal.inAppMessages.IInAppMessage
4+
import com.onesignal.inAppMessages.IInAppMessageAction
5+
import com.onesignal.inAppMessages.IInAppMessageClickResult
6+
7+
class InAppMessageClickResult(
8+
override val message: IInAppMessage,
9+
10+
override val action: IInAppMessageAction
11+
) : IInAppMessageClickResult

OneSignalSDK/onesignal/inAppMessages/src/main/java/com/onesignal/inAppMessages/internal/InAppMessagesManager.kt

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -138,12 +138,12 @@ internal class InAppMessagesManager(
138138
}
139139
}
140140

141-
override fun setInAppMessageLifecycleHandler(handler: IInAppMessageLifecycleHandler) {
141+
override fun setInAppMessageLifecycleHandler(handler: IInAppMessageLifecycleHandler?) {
142142
Logging.log(LogLevel.DEBUG, "IAMManager.setInAppMessageLifecycleHandler(handler: $handler)")
143143
_lifecycleCallback.set(handler)
144144
}
145145

146-
override fun setInAppMessageClickHandler(handler: IInAppMessageClickHandler) {
146+
override fun setInAppMessageClickHandler(handler: IInAppMessageClickHandler?) {
147147
Logging.log(LogLevel.DEBUG, "IAMManager.setInAppMessageClickHandler(handler: $handler)")
148148
_messageClickCallback.set(handler)
149149
}
@@ -515,7 +515,7 @@ internal class InAppMessagesManager(
515515
suspendifyOnThread {
516516
action.isFirstClick = message.takeActionAsUnique()
517517

518-
firePublicClickHandler(message.messageId, action)
518+
firePublicClickHandler(message, action)
519519
beginProcessingPrompts(message, action.prompts)
520520
fireClickAction(action)
521521
logInAppMessagePreviewActions(action)
@@ -525,7 +525,7 @@ internal class InAppMessagesManager(
525525
override fun onMessageActionOccurredOnMessage(message: InAppMessage, action: InAppMessageAction) {
526526
suspendifyOnThread {
527527
action.isFirstClick = message.takeActionAsUnique()
528-
firePublicClickHandler(message.messageId, action)
528+
firePublicClickHandler(message, action)
529529
beginProcessingPrompts(message, action.prompts)
530530
fireClickAction(action)
531531
fireRESTCallForClick(message, action)
@@ -695,16 +695,17 @@ internal class InAppMessagesManager(
695695
// TODO: Add more action payload preview logs here in future
696696
}
697697

698-
private suspend fun firePublicClickHandler(messageId: String, action: InAppMessageAction) {
698+
private suspend fun firePublicClickHandler(message: InAppMessage, action: InAppMessageAction) {
699699
if (!_messageClickCallback.hasCallback) {
700700
return
701701
}
702702

703703
// Send public outcome not from handler
704704
// Check that only on the handler
705705
// Any outcome sent on this callback should count as DIRECT from this IAM
706-
_influenceManager.onDirectInfluenceFromIAM(messageId)
707-
_messageClickCallback.suspendingFireOnMain { it.inAppMessageClicked(action) }
706+
_influenceManager.onDirectInfluenceFromIAM(message.messageId)
707+
val result = InAppMessageClickResult(message, action)
708+
_messageClickCallback.suspendingFireOnMain { it.inAppMessageClicked(result) }
708709
}
709710

710711
private suspend fun fireRESTCallForPageChange(message: InAppMessage, page: InAppMessagePage) {

OneSignalSDK/onesignal/notifications/src/main/java/com/onesignal/notifications/internal/Notification.kt

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package com.onesignal.notifications.internal
22

33
import androidx.core.app.NotificationCompat
4+
import com.onesignal.common.safeJSONObject
5+
import com.onesignal.common.safeString
46
import com.onesignal.core.internal.time.ITime
57
import com.onesignal.debug.internal.logging.Logging
68
import com.onesignal.notifications.BackgroundImageLayout
@@ -129,27 +131,27 @@ open class Notification : INotification {
129131
sentTime = currentTime / 1000
130132
ttl = NotificationConstants.DEFAULT_TTL_IF_NOT_IN_PAYLOAD
131133
}
132-
notificationId = customJson.optString("i")
133-
templateId = customJson.optString("ti")
134-
templateName = customJson.optString("tn")
134+
notificationId = customJson.safeString("i")
135+
templateId = customJson.safeString("ti")
136+
templateName = customJson.safeString("tn")
135137
rawPayload = currentJsonPayload.toString()
136-
additionalData = customJson.optJSONObject(NotificationConstants.PUSH_ADDITIONAL_DATA_KEY)
137-
launchURL = customJson.optString("u", null)
138-
body = currentJsonPayload.optString("alert", null)
139-
title = currentJsonPayload.optString("title", null)
140-
smallIcon = currentJsonPayload.optString("sicon", null)
141-
bigPicture = currentJsonPayload.optString("bicon", null)
142-
largeIcon = currentJsonPayload.optString("licon", null)
143-
sound = currentJsonPayload.optString("sound", null)
144-
groupKey = currentJsonPayload.optString("grp", null)
145-
groupMessage = currentJsonPayload.optString("grp_msg", null)
146-
smallIconAccentColor = currentJsonPayload.optString("bgac", null)
147-
ledColor = currentJsonPayload.optString("ledc", null)
148-
val visibility = currentJsonPayload.optString("vis", null)
138+
additionalData = customJson.safeJSONObject(NotificationConstants.PUSH_ADDITIONAL_DATA_KEY)
139+
launchURL = customJson.safeString("u")
140+
body = currentJsonPayload.safeString("alert")
141+
title = currentJsonPayload.safeString("title")
142+
smallIcon = currentJsonPayload.safeString("sicon")
143+
bigPicture = currentJsonPayload.safeString("bicon")
144+
largeIcon = currentJsonPayload.safeString("licon")
145+
sound = currentJsonPayload.safeString("sound")
146+
groupKey = currentJsonPayload.safeString("grp")
147+
groupMessage = currentJsonPayload.safeString("grp_msg")
148+
smallIconAccentColor = currentJsonPayload.safeString("bgac")
149+
ledColor = currentJsonPayload.safeString("ledc")
150+
val visibility = currentJsonPayload.safeString("vis")
149151
if (visibility != null) lockScreenVisibility = visibility.toInt()
150-
fromProjectNumber = currentJsonPayload.optString("from", null)
152+
fromProjectNumber = currentJsonPayload.safeString("from")
151153
priority = currentJsonPayload.optInt("pri", 0)
152-
val collapseKey = currentJsonPayload.optString("collapse_key", null)
154+
val collapseKey = currentJsonPayload.safeString("collapse_key")
153155
if ("do_not_collapse" != collapseKey) collapseId = collapseKey
154156
try {
155157
setActionButtonsFromData()
@@ -171,9 +173,9 @@ open class Notification : INotification {
171173
for (i in 0 until jsonActionButtons.length()) {
172174
val jsonActionButton = jsonActionButtons.getJSONObject(i)
173175
val actionButton = ActionButton()
174-
actionButton.id = jsonActionButton.optString("id", null)
175-
actionButton.text = jsonActionButton.optString("text", null)
176-
actionButton.icon = jsonActionButton.optString("icon", null)
176+
actionButton.id = jsonActionButton.safeString("id")
177+
actionButton.text = jsonActionButton.safeString("text")
178+
actionButton.icon = jsonActionButton.safeString("icon")
177179
actionBtns.add(actionButton)
178180
}
179181
actionButtons = actionBtns
@@ -184,13 +186,13 @@ open class Notification : INotification {
184186

185187
@Throws(Throwable::class)
186188
private fun setBackgroundImageLayoutFromData(currentJsonPayload: JSONObject) {
187-
val jsonStrBgImage = currentJsonPayload.optString("bg_img", null)
189+
val jsonStrBgImage = currentJsonPayload.safeString("bg_img")
188190
if (jsonStrBgImage != null) {
189191
val jsonBgImage = JSONObject(jsonStrBgImage)
190192
backgroundImageLayout = BackgroundImageLayout(
191-
jsonBgImage.optString("img"),
192-
jsonBgImage.optString("tc"),
193-
jsonBgImage.optString("bc")
193+
jsonBgImage.safeString("img"),
194+
jsonBgImage.safeString("tc"),
195+
jsonBgImage.safeString("bc")
194196
)
195197
}
196198
}
@@ -317,9 +319,9 @@ open class Notification : INotification {
317319

318320
constructor() {}
319321
constructor(jsonObject: JSONObject) {
320-
id = jsonObject.optString("id")
321-
text = jsonObject.optString("text")
322-
icon = jsonObject.optString("icon")
322+
id = jsonObject.safeString("id")
323+
text = jsonObject.safeString("text")
324+
icon = jsonObject.safeString("icon")
323325
}
324326

325327
constructor(id: String?, text: String?, icon: String?) {
Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,17 @@ package com.onesignal.notifications.internal
22

33
import com.onesignal.notifications.INotification
44
import com.onesignal.notifications.INotificationAction
5-
import com.onesignal.notifications.INotificationOpenedResult
5+
import com.onesignal.notifications.INotificationClickHandler
6+
import com.onesignal.notifications.INotificationClickResult
67

78
/**
8-
* The data provided to [INotificationOpenedHandler.notificationOpened] when a notification
9+
* The data provided to [INotificationClickHandler.notificationClicked] when a notification
910
* has been opened by the user.
1011
*/
11-
class NotificationOpenedResult(
12+
class NotificationClickResult(
1213
/** The notification that was opened by the user. **/
1314
override val notification: INotification,
1415

1516
/** The action the user took to open the notification. **/
1617
override val action: INotificationAction
17-
) : INotificationOpenedResult
18+
) : INotificationClickResult

0 commit comments

Comments
 (0)