Skip to content

Commit fc1ebe0

Browse files
authored
Merge pull request #1289 from OneSignal/fix/not-restore-disbale-channel-notifications
Fix notification disabled by channel being restored
2 parents 97df02d + 9cdb879 commit fc1ebe0

File tree

9 files changed

+232
-14
lines changed

9 files changed

+232
-14
lines changed

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,12 +95,12 @@ private static void setStatics(Context inContext) {
9595
}
9696

9797
@WorkerThread
98-
static void fromJsonPayload(OSNotificationGenerationJob notificationJob) {
98+
static boolean displayNotificationFromJsonPayload(OSNotificationGenerationJob notificationJob) {
9999
setStatics(notificationJob.getContext());
100100

101101
isRunningOnMainThreadCheck();
102102

103-
showNotification(notificationJob);
103+
return showNotification(notificationJob);
104104
}
105105

106106
/**
@@ -263,7 +263,7 @@ private static void removeNotifyOptions(NotificationCompat.Builder builder) {
263263
}
264264

265265
// Put the message into a notification and post it.
266-
private static void showNotification(OSNotificationGenerationJob notificationJob) {
266+
private static boolean showNotification(OSNotificationGenerationJob notificationJob) {
267267
int notificationId = notificationJob.getAndroidId();
268268
JSONObject fcmJson = notificationJob.getJsonPayload();
269269
String group = fcmJson.optString("grp", null);
@@ -326,6 +326,10 @@ private static void showNotification(OSNotificationGenerationJob notificationJob
326326
addXiaomiSettings(oneSignalNotificationBuilder, notification);
327327
NotificationManagerCompat.from(currentContext).notify(notificationId, notification);
328328
}
329+
330+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
331+
return OneSignalNotificationManager.areNotificationsEnabled(currentContext, notification.getChannelId());
332+
return true;
329333
}
330334

331335
private static Notification createGenericPendingIntentsForNotif(NotificationCompat.Builder notifBuilder, JSONObject gcmBundle, int notificationId) {

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

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,8 @@ static int processJobForDisplay(OSNotificationController notificationController,
133133

134134
int androidNotificationId = notificationJob.getAndroidIdWithoutCreate();
135135
boolean doDisplay = shouldDisplayNotif(notificationJob);
136+
boolean notificationDisplayed = false;
137+
136138
if (doDisplay) {
137139
androidNotificationId = notificationJob.getAndroidId();
138140
if (fromBackgroundLogic && OneSignal.shouldFireForegroundHandlers()) {
@@ -141,12 +143,13 @@ static int processJobForDisplay(OSNotificationController notificationController,
141143
// Notification will be processed by foreground user complete or timer complete
142144
return androidNotificationId;
143145
} else {
144-
GenerateNotification.fromJsonPayload(notificationJob);
146+
// Notification might end not displaying because the channel for that notification has notification disable
147+
notificationDisplayed = GenerateNotification.displayNotificationFromJsonPayload(notificationJob);
145148
}
146149
}
147150

148151
if (!notificationJob.isRestoring() && !notificationJob.isIamPreview()) {
149-
processNotification(notificationJob, opened);
152+
processNotification(notificationJob, opened, notificationDisplayed);
150153

151154
// No need to keep notification duplicate check on memory, we have database check at this point
152155
// Without removing duplicate, summary restoration might not happen
@@ -171,15 +174,20 @@ private static boolean shouldDisplayNotif(OSNotificationGenerationJob notificati
171174
/**
172175
* Save notification, updates Outcomes, and sends Received Receipt if they are enabled.
173176
*/
174-
static void processNotification(OSNotificationGenerationJob notificationJob, boolean opened) {
177+
static void processNotification(OSNotificationGenerationJob notificationJob, boolean opened, boolean notificationDisplayed) {
175178
saveNotification(notificationJob, opened);
176179

177-
if (!notificationJob.isNotificationToDisplay())
180+
if (!notificationDisplayed) {
181+
// Notification channel disable or not displayed
182+
// save notification as dismissed to avoid user re-enabling channel and notification being displayed due to restore
183+
markNotificationAsDismissed(notificationJob);
178184
return;
185+
}
179186

187+
// Logic for when the notification is displayed
180188
String notificationId = notificationJob.getApiNotificationId();
181-
OneSignal.getSessionManager().onNotificationReceived(notificationId);
182189
OSReceiveReceiptController.getInstance().sendReceiveReceipt(notificationId);
190+
OneSignal.getSessionManager().onNotificationReceived(notificationId);
183191
}
184192

185193
// Saving the notification provides the following:
@@ -244,11 +252,11 @@ private static void saveNotification(OSNotificationGenerationJob notificationJob
244252
}
245253
}
246254

247-
static void markRestoredNotificationAsDismissed(OSNotificationGenerationJob notifiJob) {
248-
OneSignal.Log(OneSignal.LOG_LEVEL.DEBUG, "Marking restored notifications as dismissed: " + notifiJob.toString());
255+
static void markNotificationAsDismissed(OSNotificationGenerationJob notifiJob) {
249256
if (notifiJob.getAndroidIdWithoutCreate() == -1)
250257
return;
251258

259+
OneSignal.Log(OneSignal.LOG_LEVEL.DEBUG, "Marking restored or disabled notifications as dismissed: " + notifiJob.toString());
252260
String whereStr = NotificationTable.COLUMN_NAME_ANDROID_NOTIFICATION_ID + " = " + notifiJob.getAndroidIdWithoutCreate();
253261

254262
OneSignalDbHelper dbHelper = OneSignalDbHelper.getInstance(notifiJob.getContext());

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,11 @@ private void notDisplayNotificationLogic(OSNotification originalNotification) {
105105
if (restoring) {
106106
// If we are not displaying a restored notification make sure we mark it as dismissed
107107
// This will prevent it from being restored again
108-
NotificationBundleProcessor.markRestoredNotificationAsDismissed(notificationJob);
108+
NotificationBundleProcessor.markNotificationAsDismissed(notificationJob);
109109
} else {
110110
// -1 is used to note never displayed
111111
notificationJob.getNotification().setAndroidNotificationId(-1);
112-
NotificationBundleProcessor.processNotification(notificationJob, true);
112+
NotificationBundleProcessor.processNotification(notificationJob, true, false);
113113
OneSignal.handleNotificationReceived(notificationJob);
114114
}
115115
}

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import android.content.Context;
44
import android.database.Cursor;
5-
import android.database.sqlite.SQLiteDatabase;
65
import android.os.Build;
76
import android.service.notification.StatusBarNotification;
87
import android.text.TextUtils;

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
11
package com.onesignal;
22

33
import android.app.Notification;
4+
import android.app.NotificationChannel;
45
import android.app.NotificationManager;
56
import android.content.Context;
67
import android.database.Cursor;
78
import android.os.Build;
89
import android.service.notification.StatusBarNotification;
10+
11+
import androidx.annotation.Nullable;
912
import androidx.annotation.RequiresApi;
1013
import androidx.core.app.NotificationCompat;
1114
import androidx.core.app.NotificationManagerCompat;
1215

1316
import java.util.ArrayList;
1417

18+
import static android.app.NotificationManager.IMPORTANCE_NONE;
19+
1520
public class OneSignalNotificationManager {
1621

1722
private static final String GROUPLESS_SUMMARY_KEY = "os_group_undefined";
@@ -157,4 +162,18 @@ static Integer getMostRecentNotifIdFromGroup(OneSignalDbHelper db, String group,
157162

158163
return recentId;
159164
}
165+
166+
@Nullable
167+
public static boolean areNotificationsEnabled(Context context, String channelId) {
168+
boolean notificationsEnabled = NotificationManagerCompat.from(context).areNotificationsEnabled();
169+
if (!notificationsEnabled)
170+
return false;
171+
172+
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
173+
NotificationChannel channel = getNotificationManager(context).getNotificationChannel(channelId);
174+
return channel == null || channel.getImportance() != IMPORTANCE_NONE;
175+
}
176+
177+
return true;
178+
}
160179
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.onesignal;
2+
3+
import android.content.Context;
4+
5+
import org.robolectric.annotation.Implementation;
6+
import org.robolectric.annotation.Implements;
7+
8+
@Implements(OneSignalNotificationManager.class)
9+
public class ShadowOneSignalNotificationManager {
10+
11+
private static boolean notificationChannelEnabled = true;
12+
13+
public static void setNotificationChannelEnabled(boolean notificationChannelEnabled) {
14+
ShadowOneSignalNotificationManager.notificationChannelEnabled = notificationChannelEnabled;
15+
}
16+
17+
@Implementation
18+
public static boolean areNotificationsEnabled(Context context, String channelId) {
19+
return notificationChannelEnabled;
20+
}
21+
22+
/**
23+
* Reset all static values (should be called before each test)
24+
*/
25+
public static void resetStatics() {
26+
notificationChannelEnabled = true;
27+
}
28+
}

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@ public class ShadowOneSignalRestClient {
4848
public static final String PUSH_USER_ID = "a2f7f967-e8cc-11e4-bed1-118f05be4511";
4949
public static final String EMAIL_USER_ID = "b007f967-98cc-11e4-bed1-118f05be4522";
5050
public static final String SMS_USER_ID = "d007f967-98cc-11e4-bed1-118f05be4522";
51+
private static final String REQUIRES_USER_PRIVACY_CONSENT = "requires_user_privacy_consent";
52+
private static final String RECEIVE_RECEIPTS_ENABLE = "receive_receipts_enable";
53+
5154
public enum REST_METHOD {
5255
GET, POST, PUT
5356
}
@@ -205,7 +208,12 @@ public static void setSuccessfulGETJSONResponses(JSONObject... responses) throws
205208
}
206209

207210
public static void setRemoteParamsRequirePrivacyConsent(boolean requirePrivacyConsent) throws JSONException {
208-
JSONObject remoteParams = new JSONObject().put("requires_user_privacy_consent", requirePrivacyConsent);
211+
JSONObject remoteParams = new JSONObject().put(REQUIRES_USER_PRIVACY_CONSENT, requirePrivacyConsent);
212+
ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(remoteParams);
213+
}
214+
215+
public static void setRemoteParamsReceiveReceiptsEnable(boolean requirePrivacyConsent) throws JSONException {
216+
JSONObject remoteParams = new JSONObject().put(RECEIVE_RECEIPTS_ENABLE, requirePrivacyConsent);
209217
ShadowOneSignalRestClient.setRemoteParamsGetHtmlResponse(remoteParams);
210218
}
211219

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

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
import com.onesignal.ShadowNotificationManagerCompat;
8282
import com.onesignal.ShadowOSUtils;
8383
import com.onesignal.ShadowOneSignal;
84+
import com.onesignal.ShadowOneSignalNotificationManager;
8485
import com.onesignal.ShadowOneSignalRestClient;
8586
import com.onesignal.ShadowPushRegistratorADM;
8687
import com.onesignal.ShadowPushRegistratorFCM;
@@ -222,6 +223,7 @@ private static void getGetTagsHandler() {
222223
private static OSSMSSubscriptionStateChanges lastSMSSubscriptionStateChanges;
223224

224225
private static void cleanUp() throws Exception {
226+
lastServiceNotificationReceivedEvent = null;
225227
lastNotificationOpenedBody = null;
226228
lastGetTags = null;
227229
lastEmailSubscriptionStateChanges = null;
@@ -1227,6 +1229,154 @@ public void testNotificationReceivedWhenAppInFocus() throws Exception {
12271229
assertEquals("Robo test message", notificationReceivedBody);
12281230
}
12291231

1232+
// Start Received Request tests (report_received)
1233+
1234+
@Test
1235+
@Config(shadows = { ShadowGenerateNotification.class })
1236+
public void testNotificationReceivedSendReceivedRequest_WhenAppInBackground() throws Exception {
1237+
// First init run for appId to be saved
1238+
// At least OneSignal was init once for user to be subscribed
1239+
// If this doesn't' happen, notifications will not arrive
1240+
OneSignal.setAppId(ONESIGNAL_APP_ID);
1241+
OneSignal.initWithContext(blankActivity);
1242+
threadAndTaskWait();
1243+
fastColdRestartApp();
1244+
1245+
ShadowOneSignalRestClient.setRemoteParamsReceiveReceiptsEnable(true);
1246+
// 1. initWithContext is called when startProcessing notification
1247+
OneSignal.initWithContext(blankActivity.getApplicationContext());
1248+
// 2. Receive a notification in background
1249+
FCMBroadcastReceiver_processBundle(blankActivity, getBaseNotifBundle());
1250+
threadAndTaskWait();
1251+
1252+
// 3. Check that report_received where sent
1253+
assertEquals(4, ShadowOneSignalRestClient.requests.size());
1254+
assertEquals("notifications/UUID/report_received", ShadowOneSignalRestClient.lastUrl);
1255+
}
1256+
1257+
@Test
1258+
@Config(shadows = { ShadowGenerateNotification.class })
1259+
public void testNotificationReceivedSendReceivedRequest_WhenAppInForeground() throws Exception {
1260+
ShadowOneSignalRestClient.setRemoteParamsReceiveReceiptsEnable(true);
1261+
// First init run for appId to be saved
1262+
// At least OneSignal was init once for user to be subscribed
1263+
// If this doesn't' happen, notifications will not arrive
1264+
OneSignal.setAppId(ONESIGNAL_APP_ID);
1265+
OneSignal.initWithContext(blankActivity);
1266+
threadAndTaskWait();
1267+
1268+
// 1. Receive a notification in background
1269+
FCMBroadcastReceiver_processBundle(blankActivity, getBaseNotifBundle());
1270+
threadAndTaskWait();
1271+
1272+
// 2. Check that report_received where sent
1273+
assertEquals(3, ShadowOneSignalRestClient.requests.size());
1274+
assertEquals("notifications/UUID/report_received", ShadowOneSignalRestClient.lastUrl);
1275+
}
1276+
1277+
@Test
1278+
@Config(shadows = { ShadowGenerateNotification.class })
1279+
public void testNotificationReceivedNoSendReceivedRequest_WhenDisabled() throws Exception {
1280+
ShadowOneSignalRestClient.setRemoteParamsReceiveReceiptsEnable(false);
1281+
// First init run for appId to be saved
1282+
// At least OneSignal was init once for user to be subscribed
1283+
// If this doesn't' happen, notifications will not arrive
1284+
OneSignal.setAppId(ONESIGNAL_APP_ID);
1285+
OneSignal.initWithContext(blankActivity);
1286+
threadAndTaskWait();
1287+
1288+
// 1. Receive a notification in background
1289+
FCMBroadcastReceiver_processBundle(blankActivity, getBaseNotifBundle());
1290+
threadAndTaskWait();
1291+
1292+
// 2. Check that report_received where sent
1293+
assertEquals(2, ShadowOneSignalRestClient.requests.size());
1294+
assertNotEquals("notifications/UUID/report_received", ShadowOneSignalRestClient.lastUrl);
1295+
}
1296+
1297+
@Test
1298+
@Config(shadows = { ShadowGenerateNotification.class })
1299+
public void testNotificationReceivedNoSendReceivedRequest_WhenNotificationNotDisplayed() throws Exception {
1300+
// 1. Setup correct notification extension service class
1301+
startRemoteNotificationReceivedHandlerService("com.test.onesignal.MainOneSignalClassRunner$" +
1302+
"RemoteNotificationReceivedHandler_NoDisplay");
1303+
1304+
ShadowOneSignalRestClient.setRemoteParamsReceiveReceiptsEnable(true);
1305+
// First init run for appId to be saved
1306+
// At least OneSignal was init once for user to be subscribed
1307+
// If this doesn't' happen, notifications will not arrive
1308+
OneSignal.setAppId(ONESIGNAL_APP_ID);
1309+
OneSignal.initWithContext(blankActivity);
1310+
threadAndTaskWait();
1311+
1312+
// 2. Receive a notification in background
1313+
FCMBroadcastReceiver_processBundle(blankActivity, getBaseNotifBundle());
1314+
threadAndTaskWait();
1315+
1316+
// 3. Make sure service was called
1317+
assertNotNull(lastServiceNotificationReceivedEvent);
1318+
1319+
// 4. Check that report_received where sent
1320+
assertEquals(2, ShadowOneSignalRestClient.requests.size());
1321+
assertNotEquals("notifications/UUID/report_received", ShadowOneSignalRestClient.lastUrl);
1322+
}
1323+
1324+
@Test
1325+
@Config(sdk = 26, shadows = { ShadowGenerateNotification.class, ShadowOneSignalNotificationManager.class })
1326+
public void testNotificationReceivedNoSendReceivedRequest_WhenNotificationNotDisplayed_DisabledByChannel() throws Exception {
1327+
// 1. Setup correct notification extension service class
1328+
startRemoteNotificationReceivedHandlerService("com.test.onesignal.MainOneSignalClassRunner$" +
1329+
"RemoteNotificationReceivedHandler");
1330+
1331+
ShadowOneSignalRestClient.setRemoteParamsReceiveReceiptsEnable(true);
1332+
ShadowOneSignalNotificationManager.setNotificationChannelEnabled(false);
1333+
// First init run for appId to be saved
1334+
// At least OneSignal was init once for user to be subscribed
1335+
// If this doesn't' happen, notifications will not arrive
1336+
OneSignal.setAppId(ONESIGNAL_APP_ID);
1337+
OneSignal.initWithContext(blankActivity);
1338+
threadAndTaskWait();
1339+
1340+
// 2. Receive a notification in background
1341+
FCMBroadcastReceiver_processBundle(blankActivity, getBaseNotifBundle());
1342+
threadAndTaskWait();
1343+
1344+
// 3. Make sure service was called
1345+
assertNotNull(lastServiceNotificationReceivedEvent);
1346+
1347+
// 4. Check that report_received where sent
1348+
assertEquals(2, ShadowOneSignalRestClient.requests.size());
1349+
assertNotEquals("notifications/UUID/report_received", ShadowOneSignalRestClient.lastUrl);
1350+
}
1351+
1352+
/**
1353+
* @see #testNotificationReceivedNoSendReceivedRequest_WhenNotificationNotDisplayed
1354+
*/
1355+
public static class RemoteNotificationReceivedHandler_NoDisplay implements OneSignal.OSRemoteNotificationReceivedHandler {
1356+
1357+
@Override
1358+
public void remoteNotificationReceived(Context context, OSNotificationReceivedEvent receivedEvent) {
1359+
lastServiceNotificationReceivedEvent = receivedEvent;
1360+
1361+
receivedEvent.complete(null);
1362+
}
1363+
}
1364+
1365+
/**
1366+
* @see #testNotificationReceivedNoSendReceivedRequest_WhenNotificationNotDisplayed_DisabledByChannel
1367+
*/
1368+
public static class RemoteNotificationReceivedHandler implements OneSignal.OSRemoteNotificationReceivedHandler {
1369+
1370+
@Override
1371+
public void remoteNotificationReceived(Context context, OSNotificationReceivedEvent receivedEvent) {
1372+
lastServiceNotificationReceivedEvent = receivedEvent;
1373+
1374+
receivedEvent.complete(receivedEvent.getNotification());
1375+
}
1376+
}
1377+
1378+
// End Received Request tests (report_received)
1379+
12301380
@Test
12311381
@Config(shadows = {ShadowBadgeCountUpdater.class})
12321382
public void testBadgeClearOnFirstStart() throws Exception {

0 commit comments

Comments
 (0)