Skip to content

Commit 452d571

Browse files
authored
Merge pull request #870 from OneSignal/feature/base-receive-receipt
Feature/base receive receipt
2 parents 8df21ae + de281b1 commit 452d571

11 files changed

+211
-14
lines changed

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

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -145,15 +145,16 @@ private static void saveAndProcessNotification(Context context, Bundle bundle, b
145145
}
146146

147147
/**
148-
* Must call this method instead of saveNotification
149-
*
150-
* This method save the last notification that might influence session
148+
* Save notification, updates Outcomes, and sends Received Receipt if they are enabled.
151149
*/
152150
static void processNotification(NotificationGenerationJob notifiJob, boolean opened) {
153151
saveNotification(notifiJob, opened);
154-
if (notifiJob.isNotificationToDisplay()) {
155-
OutcomesUtils.markLastNotificationReceived(notifiJob.getApiNotificationId());
156-
}
152+
153+
if (!notifiJob.isNotificationToDisplay())
154+
return;
155+
String notificationId = notifiJob.getApiNotificationId();
156+
OutcomesUtils.markLastNotificationReceived(notificationId);
157+
OSReceiveReceiptController.getInstance().sendReceiveReceipt(notificationId);
157158
}
158159

159160
// Saving the notification provides the following:

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,4 +112,5 @@ void setAndroidIdWithOutOverriding(Integer id) {
112112
boolean hasExtender() {
113113
return overrideSettings != null && overrideSettings.extender != null;
114114
}
115+
115116
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/**
2+
* Modified MIT License
3+
* <p>
4+
* Copyright 2019 OneSignal
5+
* <p>
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
* <p>
13+
* 1. The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
* <p>
16+
* 2. All copies of substantial portions of the Software may only be used in connection
17+
* with services provided by OneSignal.
18+
* <p>
19+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
* THE SOFTWARE.
26+
*/
27+
28+
package com.onesignal;
29+
30+
import android.support.annotation.NonNull;
31+
32+
class OSReceiveReceiptController {
33+
34+
private final OSReceiveReceiptRepository repository;
35+
36+
private static OSReceiveReceiptController sInstance;
37+
private OSReceiveReceiptController() {
38+
this.repository = new OSReceiveReceiptRepository();
39+
}
40+
public static synchronized OSReceiveReceiptController getInstance() {
41+
if (sInstance == null)
42+
sInstance = new OSReceiveReceiptController();
43+
return sInstance;
44+
}
45+
46+
void sendReceiveReceipt(@NonNull final String notificationId) {
47+
String appId = OneSignal.appId == null || OneSignal.appId.isEmpty() ? OneSignal.getSavedAppId() : OneSignal.appId;
48+
String playerId = OneSignal.getUserId();
49+
50+
if (!isReceiveReceiptEnabled()) {
51+
OneSignal.Log(OneSignal.LOG_LEVEL.DEBUG, "sendReceiveReceipt disable");
52+
return;
53+
}
54+
55+
OneSignal.Log(OneSignal.LOG_LEVEL.DEBUG, "sendReceiveReceipt appId: " + appId + " playerId: " + playerId + " notificationId: " + notificationId);
56+
repository.sendReceiveReceipt(appId, playerId, notificationId, new OneSignalRestClient.ResponseHandler() {
57+
@Override
58+
void onSuccess(String response) {
59+
OneSignal.Log(OneSignal.LOG_LEVEL.DEBUG, "Receive receipt sent for notificationID: " + notificationId);
60+
}
61+
62+
@Override
63+
void onFailure(int statusCode, String response, Throwable throwable) {
64+
OneSignal.Log(OneSignal.LOG_LEVEL.ERROR, "Receive receipt failed with statusCode: " + statusCode + " response: " + response);
65+
}
66+
});
67+
}
68+
69+
private boolean isReceiveReceiptEnabled() {
70+
return OneSignalPrefs.getBool(
71+
OneSignalPrefs.PREFS_ONESIGNAL,
72+
OneSignalPrefs.PREFS_OS_RECEIVE_RECEIPTS_ENABLED,
73+
false
74+
);
75+
}
76+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* Modified MIT License
3+
* <p>
4+
* Copyright 2019 OneSignal
5+
* <p>
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to deal
8+
* in the Software without restriction, including without limitation the rights
9+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10+
* copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
* <p>
13+
* 1. The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
* <p>
16+
* 2. All copies of substantial portions of the Software may only be used in connection
17+
* with services provided by OneSignal.
18+
* <p>
19+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
* THE SOFTWARE.
26+
*/
27+
28+
package com.onesignal;
29+
30+
import android.support.annotation.NonNull;
31+
32+
import org.json.JSONException;
33+
import org.json.JSONObject;
34+
35+
class OSReceiveReceiptRepository {
36+
37+
private static final String APP_ID = "app_id";
38+
private static final String PLAYER_ID = "player_id";
39+
40+
void sendReceiveReceipt(@NonNull String appId, @NonNull String playerId, @NonNull String notificationId, @NonNull OneSignalRestClient.ResponseHandler responseHandler) {
41+
try {
42+
JSONObject jsonBody = new JSONObject()
43+
.put(APP_ID, appId)
44+
.put(PLAYER_ID, playerId);
45+
46+
OneSignalRestClient.put("notifications/" + notificationId + "/report_received", jsonBody, responseHandler);
47+
} catch (JSONException e) {
48+
OneSignal.Log(OneSignal.LOG_LEVEL.ERROR, "Generating direct receive receipt:JSON Failed.", e);
49+
}
50+
}
51+
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -998,6 +998,12 @@ public void complete(OneSignalRemoteParams.Params params) {
998998
OneSignalPrefs.PREFS_OS_CLEAR_GROUP_SUMMARY_CLICK,
999999
remoteParams.clearGroupOnSummaryClick
10001000
);
1001+
OneSignalPrefs.saveBool(
1002+
OneSignalPrefs.PREFS_ONESIGNAL,
1003+
OneSignalPrefs.PREFS_OS_RECEIVE_RECEIPTS_ENABLED,
1004+
remoteParams.receiveReceiptEnabled
1005+
);
1006+
10011007
OutcomesUtils.saveOutcomesParams(params.outcomesParams);
10021008

10031009
NotificationChannelManager.processChannelList(

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ class OneSignalPrefs {
8080
public static final String PREFS_OS_DISPLAYED_IAMS = "PREFS_OS_DISPLAYED_IAMS";
8181
public static final String PREFS_OS_IMPRESSIONED_IAMS = "PREFS_OS_IMPRESSIONED_IAMS";
8282
public static final String PREFS_OS_CLICKED_CLICK_IDS_IAMS = "PREFS_OS_CLICKED_CLICK_IDS_IAMS";
83+
public static final String PREFS_OS_RECEIVE_RECEIPTS_ENABLED = "PREFS_OS_RECEIVE_RECEIPTS_ENABLED";
8384
public static final String PREFS_OS_LAST_ATTRIBUTED_NOTIFICATION_OPEN = "PREFS_OS_LAST_ATTRIBUTED_NOTIFICATION_OPEN";
8485
public static final String PREFS_OS_LAST_NOTIFICATIONS_RECEIVED = "PREFS_OS_LAST_NOTIFICATIONS_RECEIVED";
8586
public static final String PREFS_OS_NOTIFICATION_LIMIT = "PREFS_OS_NOTIFICATION_LIMIT";
@@ -90,7 +91,6 @@ class OneSignalPrefs {
9091
public static final String PREFS_OS_OUTCOMES_CURRENT_SESSION = "PREFS_OS_OUTCOMES_CURRENT_SESSION";
9192
public static final String PREFS_OS_UNIQUE_OUTCOME_EVENTS_SENT = "PREFS_OS_UNIQUE_OUTCOME_EVENTS_SENT";
9293

93-
9494
// PLAYER PURCHASE KEYS
9595
static final String PREFS_PURCHASE_TOKENS = "purchaseTokens";
9696
static final String PREFS_EXISTING_PURCHASES = "ExistingPurchases";

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ static class Params {
2727
boolean firebaseAnalytics;
2828
boolean restoreTTLFilter;
2929
boolean clearGroupOnSummaryClick;
30+
boolean receiveReceiptEnabled;
3031
OutcomesParams outcomesParams;
3132
}
3233

@@ -107,6 +108,7 @@ static private void processJson(String json, final @NonNull CallBack callBack) {
107108
restoreTTLFilter = responseJson.optBoolean("restore_ttl_filter", true);
108109
googleProjectNumber = responseJson.optString("android_sender_id", null);
109110
clearGroupOnSummaryClick = responseJson.optBoolean("clear_group_on_summary_click", true);
111+
receiveReceiptEnabled = responseJson.optBoolean("receive_receipts_enable", false);
110112
outcomesParams = new OutcomesParams();
111113

112114
//Process outcomes params
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.onesignal;
2+
3+
import org.robolectric.annotation.Implementation;
4+
import org.robolectric.annotation.Implements;
5+
6+
@Implements(OSReceiveReceiptController.class)
7+
public class ShadowReceiveReceiptController {
8+
9+
@Implementation
10+
public boolean isReceiveReceiptEnabled() {
11+
return true;
12+
}
13+
}

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

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
import com.onesignal.ShadowOSWebView;
7373
import com.onesignal.ShadowOneSignal;
7474
import com.onesignal.ShadowOneSignalRestClient;
75+
import com.onesignal.ShadowReceiveReceiptController;
7576
import com.onesignal.ShadowRoboNotificationManager;
7677
import com.onesignal.ShadowRoboNotificationManager.PostedNotification;
7778
import com.onesignal.StaticResetHelper;
@@ -106,8 +107,11 @@
106107
import static com.onesignal.OneSignalPackagePrivateHelper.NotificationOpenedProcessor_processFromContext;
107108
import static com.onesignal.OneSignalPackagePrivateHelper.NotificationSummaryManager_updateSummaryNotificationAfterChildRemoved;
108109
import static com.onesignal.OneSignalPackagePrivateHelper.createInternalPayloadBundle;
110+
import static com.test.onesignal.RestClientAsserts.assertReportReceivedAtIndex;
111+
import static com.test.onesignal.RestClientAsserts.assertRestCalls;
109112
import static com.test.onesignal.TestHelpers.advanceSystemTimeBy;
110113
import static com.test.onesignal.TestHelpers.threadAndTaskWait;
114+
111115
import static junit.framework.Assert.assertEquals;
112116
import static junit.framework.Assert.assertFalse;
113117
import static junit.framework.Assert.assertNotNull;
@@ -296,8 +300,6 @@ public void shouldSetCorrectNumberOfButtonsOnSummaryNotification() throws Except
296300
assertEquals(1, postedSummaryNotification.notif.actions.length);
297301
}
298302

299-
300-
301303
@Test
302304
public void shouldCancelAllNotificationsPartOfAGroup() throws Exception {
303305
// Setup - Init
@@ -1222,6 +1224,34 @@ public void shouldShowInAppPreviewWhenOpeningPreviewNotification() throws Except
12221224

12231225
assertEquals("PGh0bWw+PC9odG1sPg==", ShadowOSWebView.lastData);
12241226
}
1227+
1228+
@Test
1229+
@Config(shadows = { ShadowReceiveReceiptController.class })
1230+
public void shouldSendReceivedReceiptWhenEnabled() throws Exception {
1231+
String appId = "b2f7f966-d8cc-11e4-bed1-df8f05be55ba";
1232+
OneSignal.init(blankActivity, "123456789", appId);
1233+
threadAndTaskWait();
1234+
NotificationBundleProcessor_ProcessFromGCMIntentService(blankActivity, getBaseNotifBundle(), null);
1235+
threadAndTaskWait();
1236+
1237+
assertReportReceivedAtIndex(
1238+
2,
1239+
"UUID",
1240+
new JSONObject().put("app_id", appId).put("player_id", ShadowOneSignalRestClient.pushUserId)
1241+
);
1242+
}
1243+
1244+
@Test
1245+
public void shouldNotSendReceivedReceiptWhenDisabled() throws Exception {
1246+
String appId = "b2f7f966-d8cc-11e4-bed1-df8f05be55ba";
1247+
OneSignal.init(blankActivity, "123456789", appId);
1248+
threadAndTaskWait();
1249+
NotificationBundleProcessor_ProcessFromGCMIntentService(blankActivity, getBaseNotifBundle(), null);
1250+
threadAndTaskWait();
1251+
1252+
assertRestCalls(2);
1253+
}
1254+
12251255

12261256
private OSNotification lastNotificationReceived;
12271257
@Test

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

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
import com.onesignal.ShadowOneSignal;
7878
import com.onesignal.ShadowOneSignalRestClient;
7979
import com.onesignal.ShadowPushRegistratorGCM;
80+
import com.onesignal.ShadowReceiveReceiptController;
8081
import com.onesignal.ShadowRoboNotificationManager;
8182
import com.onesignal.StaticResetHelper;
8283
import com.onesignal.SyncJobService;
@@ -137,6 +138,8 @@
137138
import static junit.framework.Assert.assertNull;
138139
import static junit.framework.Assert.assertTrue;
139140
import static org.hamcrest.CoreMatchers.not;
141+
import static org.hamcrest.core.Is.is;
142+
import static org.junit.Assert.assertNotEquals;
140143
import static org.junit.Assert.assertThat;
141144
import static org.robolectric.Shadows.shadowOf;
142145

@@ -923,12 +926,13 @@ public void notificationReceived(OSNotification notification) {
923926
Bundle bundle = getBaseNotifBundle();
924927
boolean processResult = GcmBroadcastReceiver_processBundle(blankActivity, bundle);
925928
threadAndTaskWait();
926-
assertEquals(null, notificationOpenedMessage);
929+
930+
assertNull(notificationOpenedMessage);
927931
assertFalse(processResult);
928932
// NotificationBundleProcessor.Process(...) will be called if processResult is true as a service
929933
NotificationBundleProcessor_Process(blankActivity, false, bundleAsJSONObject(bundle), null);
930934
assertEquals("Robo test message", notificationReceivedBody);
931-
assertFalse(0 == androidNotificationId);
935+
assertNotEquals(0, androidNotificationId);
932936

933937
// Don't fire for duplicates
934938
notificationOpenedMessage = null;
@@ -938,8 +942,8 @@ public void notificationReceived(OSNotification notification) {
938942

939943
GcmBroadcastReceiver_processBundle(blankActivity, bundle);
940944
threadAndTaskWait();
941-
assertEquals(null, notificationOpenedMessage);
942-
assertEquals(null, notificationReceivedBody);
945+
assertNull(notificationOpenedMessage);
946+
assertNull(notificationReceivedBody);
943947

944948
// Test that only NotificationReceivedHandler fires
945949
OneSignal.setInFocusDisplaying(OneSignal.OSInFocusDisplayOption.None);
@@ -949,7 +953,6 @@ public void notificationReceived(OSNotification notification) {
949953

950954
GcmBroadcastReceiver_processBundle(blankActivity, bundle);
951955
threadAndTaskWait();
952-
assertEquals(null, notificationOpenedMessage);
953956
assertNull(notificationOpenedMessage);
954957
assertEquals("Robo test message", notificationReceivedBody);
955958
}

0 commit comments

Comments
 (0)