Skip to content

Commit dda19da

Browse files
authored
Merge pull request #1484 from OneSignal/fix/notification-processed-twice
Use two `Workers` to display notification and send receive receipt
2 parents 1fcacef + d80b60b commit dda19da

20 files changed

+143
-290
lines changed

OneSignalSDK/build.gradle

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ buildscript {
88
targetSdkVersion: 30
99
]
1010
androidGradlePluginVersion = '3.6.2'
11-
androidConcurrentFutures = '1.1.0'
1211
googleServicesGradlePluginVersion = '4.3.2'
1312
huaweiAgconnectVersion = '1.2.1.301'
1413
huaweiHMSPushVersion = '5.3.0.304'

OneSignalSDK/onesignal/build.gradle

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,6 @@ dependencies {
4848
// Required for GoogleApiAvailability
4949
implementation 'com.google.android.gms:play-services-base:[17.0.0, 17.6.99]'
5050

51-
implementation("androidx.concurrent:concurrent-futures:$androidConcurrentFutures")
52-
5351
// firebase-messaging:18.0.0 is the last version before going to AndroidX
5452
// firebase-messaging:19.0.0 is the first version using AndroidX
5553
api 'com.google.firebase:firebase-messaging:[19.0.0, 22.0.99]'

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

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,6 @@
3838
import androidx.annotation.NonNull;
3939
import androidx.annotation.Nullable;
4040
import androidx.annotation.WorkerThread;
41-
import androidx.concurrent.futures.CallbackToFutureAdapter;
42-
import androidx.work.ListenableWorker;
4341

4442
import com.onesignal.OneSignalDbContract.NotificationTable;
4543

@@ -100,8 +98,7 @@ public void onResult(boolean result) {
10098
jsonStrPayload,
10199
shownTimeStamp,
102100
isRestoring,
103-
false,
104-
true);
101+
false);
105102

106103
// Delay to prevent CPU spikes.
107104
// Normally more than one notification is restored at a time.
@@ -164,11 +161,6 @@ private static int processJobForDisplay(OSNotificationController notificationCon
164161
String osNotificationId = OSNotificationFormatHelper.getOSNotificationIdFromJson(notificationController.getNotificationJob().getJsonPayload());
165162
OSNotificationWorkManager.removeNotificationIdProcessed(osNotificationId);
166163
OneSignal.handleNotificationReceived(notificationJob);
167-
} else {
168-
CallbackToFutureAdapter.Completer<ListenableWorker.Result> callbackCompleter = notificationJob.getCallbackCompleter();
169-
OneSignal.Log(OneSignal.LOG_LEVEL.DEBUG, "Process notification restored or IAM with callback completer: " + callbackCompleter);
170-
if (callbackCompleter != null)
171-
callbackCompleter.set(ListenableWorker.Result.success());
172164
}
173165

174166
return androidNotificationId;
@@ -183,22 +175,18 @@ private static boolean shouldDisplayNotification(OSNotificationGenerationJob not
183175
*/
184176
static void processNotification(OSNotificationGenerationJob notificationJob, boolean opened, boolean notificationDisplayed) {
185177
saveNotification(notificationJob, opened);
186-
CallbackToFutureAdapter.Completer<ListenableWorker.Result> callbackCompleter = notificationJob.getCallbackCompleter();
187178

188179
if (!notificationDisplayed) {
189180
// Notification channel disable or not displayed
190181
// save notification as dismissed to avoid user re-enabling channel and notification being displayed due to restore
191182
markNotificationAsDismissed(notificationJob);
192-
193-
OneSignal.Log(OneSignal.LOG_LEVEL.DEBUG, "Process notification not displayed with callback completer: " + callbackCompleter);
194-
if (callbackCompleter != null)
195-
callbackCompleter.set(ListenableWorker.Result.success());
196183
return;
197184
}
198185

199186
// Logic for when the notification is displayed
200187
String notificationId = notificationJob.getApiNotificationId();
201-
OSReceiveReceiptController.getInstance().sendReceiveReceipt(callbackCompleter, notificationId);
188+
Context context = notificationJob.getContext();
189+
OSReceiveReceiptController.getInstance().beginEnqueueingWork(context, notificationId);
202190
OneSignal.getSessionManager().onNotificationReceived(notificationId);
203191
}
204192

@@ -439,8 +427,7 @@ public void onResult(boolean result) {
439427
jsonPayload.toString(),
440428
timestamp,
441429
isRestoring,
442-
isHighPriority,
443-
true);
430+
isHighPriority);
444431

445432
bundleResult.setWorkManagerProcessing(true);
446433
notificationProcessingCallback.onResult(true);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ private static void restoreSummary(Context context, String group) {
146146
null
147147
);
148148

149-
OSNotificationRestoreWorkManager.showNotificationsFromCursor(context, cursor, 0, true);
149+
OSNotificationRestoreWorkManager.showNotificationsFromCursor(context, cursor, 0);
150150
} catch (Throwable t) {
151151
OneSignal.Log(OneSignal.LOG_LEVEL.ERROR, "Error restoring notification records! ", t);
152152
} finally {

OneSignalSDK/onesignal/src/main/java/com/onesignal/OSDelayTaskController.kt

Lines changed: 0 additions & 40 deletions
This file was deleted.

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

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@
3434
import android.content.Context;
3535

3636
import androidx.annotation.Nullable;
37-
import androidx.concurrent.futures.CallbackToFutureAdapter;
38-
import androidx.work.ListenableWorker;
3937

4038
import org.json.JSONObject;
4139

@@ -46,7 +44,6 @@ public class OSNotificationController {
4644
static final String GOOGLE_SENT_TIME_KEY = "google.sent_time";
4745
static final String GOOGLE_TTL_KEY = "google.ttl";
4846

49-
private final CallbackToFutureAdapter.Completer<ListenableWorker.Result> callbackCompleter;
5047
private final OSNotificationGenerationJob notificationJob;
5148
private boolean restoring;
5249
private boolean fromBackgroundLogic;
@@ -55,12 +52,9 @@ public class OSNotificationController {
5552
this.restoring = restoring;
5653
this.fromBackgroundLogic = fromBackgroundLogic;
5754
this.notificationJob = notificationJob;
58-
this.callbackCompleter = notificationJob.getCallbackCompleter();
5955
}
6056

61-
OSNotificationController(CallbackToFutureAdapter.Completer<ListenableWorker.Result> callbackCompleter,
62-
Context context, OSNotification notification, JSONObject jsonPayload, boolean restoring, boolean fromBackgroundLogic, Long timestamp) {
63-
this.callbackCompleter = callbackCompleter;
57+
OSNotificationController(Context context, OSNotification notification, JSONObject jsonPayload, boolean restoring, boolean fromBackgroundLogic, Long timestamp) {
6458
this.restoring = restoring;
6559
this.fromBackgroundLogic = fromBackgroundLogic;
6660

@@ -74,7 +68,7 @@ public class OSNotificationController {
7468
* @see OSNotificationGenerationJob
7569
*/
7670
private OSNotificationGenerationJob createNotificationJobFromCurrent(Context context, OSNotification notification, JSONObject jsonPayload, Long timestamp) {
77-
OSNotificationGenerationJob notificationJob = new OSNotificationGenerationJob(callbackCompleter, context);
71+
OSNotificationGenerationJob notificationJob = new OSNotificationGenerationJob(context);
7872
notificationJob.setJsonPayload(jsonPayload);
7973
notificationJob.setShownTimeStamp(timestamp);
8074
notificationJob.setRestoring(restoring);

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

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,12 @@
3030
import android.content.Context;
3131
import android.net.Uri;
3232

33-
import androidx.annotation.Nullable;
34-
import androidx.concurrent.futures.CallbackToFutureAdapter;
35-
import androidx.work.ListenableWorker;
36-
3733
import org.json.JSONObject;
3834

3935
import java.security.SecureRandom;
4036

4137
public class OSNotificationGenerationJob {
4238

43-
private CallbackToFutureAdapter.Completer<ListenableWorker.Result> callbackCompleter;
4439
private OSNotification notification;
4540
private Context context;
4641
private JSONObject jsonPayload;
@@ -56,11 +51,6 @@ public class OSNotificationGenerationJob {
5651
private Uri orgSound;
5752

5853
OSNotificationGenerationJob(Context context) {
59-
this(null, context);
60-
}
61-
62-
OSNotificationGenerationJob(CallbackToFutureAdapter.Completer<ListenableWorker.Result> callbackCompleter, Context context) {
63-
this.callbackCompleter = callbackCompleter;
6454
this.context = context;
6555
}
6656

@@ -74,11 +64,6 @@ public class OSNotificationGenerationJob {
7464
this.notification = notification;
7565
}
7666

77-
@Nullable
78-
public CallbackToFutureAdapter.Completer<ListenableWorker.Result> getCallbackCompleter() {
79-
return callbackCompleter;
80-
}
81-
8267
/**
8368
* Get the notification title from the payload
8469
*/

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ private static void queryAndRestoreNotificationsAndBadgeCount(
104104
OneSignalDbContract.NotificationTable._ID + " DESC", // sort order, new to old
105105
NotificationLimitManager.MAX_NUMBER_OF_NOTIFICATIONS_STR // limit
106106
);
107-
showNotificationsFromCursor(context, cursor, DELAY_BETWEEN_NOTIFICATION_RESTORES_MS, false);
107+
showNotificationsFromCursor(context, cursor, DELAY_BETWEEN_NOTIFICATION_RESTORES_MS);
108108
BadgeCountUpdater.update(dbHelper, context);
109109
} catch (Throwable t) {
110110
OneSignal.Log(OneSignal.LOG_LEVEL.ERROR, "Error restoring notification records! ", t);
@@ -144,7 +144,7 @@ private static void skipVisibleNotifications(Context context, StringBuilder dbQu
144144
* @param cursor - Source cursor to generate notifications from
145145
* @param delay - Delay to slow down process to ensure we don't spike CPU and I/O on the device
146146
*/
147-
static void showNotificationsFromCursor(Context context, Cursor cursor, int delay, boolean needsWorkerThread) {
147+
static void showNotificationsFromCursor(Context context, Cursor cursor, int delay) {
148148
if (!cursor.moveToFirst())
149149
return;
150150

@@ -161,8 +161,7 @@ static void showNotificationsFromCursor(Context context, Cursor cursor, int dela
161161
fullData,
162162
dateTime,
163163
true,
164-
false,
165-
needsWorkerThread
164+
false
166165
);
167166

168167
if (delay > 0)

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

Lines changed: 21 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,13 @@
33
import android.content.Context;
44

55
import androidx.annotation.NonNull;
6-
import androidx.annotation.Nullable;
7-
import androidx.concurrent.futures.CallbackToFutureAdapter;
86
import androidx.work.Data;
97
import androidx.work.ExistingWorkPolicy;
10-
import androidx.work.ListenableWorker;
118
import androidx.work.OneTimeWorkRequest;
129
import androidx.work.WorkManager;
10+
import androidx.work.Worker;
1311
import androidx.work.WorkerParameters;
1412

15-
import com.google.common.util.concurrent.ListenableFuture;
16-
1713
import org.json.JSONException;
1814
import org.json.JSONObject;
1915

@@ -23,7 +19,6 @@
2319

2420
class OSNotificationWorkManager {
2521

26-
private static final String OS_NOTIFICATION_ID = "os_bnotification_id";
2722
private static final String ANDROID_NOTIF_ID_WORKER_DATA_PARAM = "android_notif_id";
2823
private static final String JSON_PAYLOAD_WORKER_DATA_PARAM = "json_payload";
2924
private static final String TIMESTAMP_WORKER_DATA_PARAM = "timestamp";
@@ -54,20 +49,9 @@ static void removeNotificationIdProcessed(String osNotificationId) {
5449
}
5550

5651
static void beginEnqueueingWork(Context context, String osNotificationId, int androidNotificationId, String jsonPayload, long timestamp,
57-
boolean isRestoring, boolean isHighPriority, boolean needsWorkerThread) {
58-
if (!needsWorkerThread) {
59-
try {
60-
JSONObject jsonPayloadObject = new JSONObject(jsonPayload);
61-
processNotificationData(context, androidNotificationId, jsonPayloadObject, isRestoring, timestamp);
62-
} catch (JSONException e) {
63-
OneSignal.onesignalLog(OneSignal.LOG_LEVEL.ERROR, "Error occurred parsing jsonPayload to JSONObject in beginEnqueueingWork e: " + e.getMessage());
64-
e.printStackTrace();
65-
}
66-
return;
67-
}
52+
boolean isRestoring, boolean isHighPriority) {
6853
// TODO: Need to figure out how to implement the isHighPriority param
6954
Data inputData = new Data.Builder()
70-
.putString(OS_NOTIFICATION_ID, osNotificationId)
7155
.putInt(ANDROID_NOTIF_ID_WORKER_DATA_PARAM, androidNotificationId)
7256
.putString(JSON_PAYLOAD_WORKER_DATA_PARAM, jsonPayload)
7357
.putLong(TIMESTAMP_WORKER_DATA_PARAM, timestamp)
@@ -83,29 +67,15 @@ static void beginEnqueueingWork(Context context, String osNotificationId, int an
8367
.enqueueUniqueWork(osNotificationId, ExistingWorkPolicy.KEEP, workRequest);
8468
}
8569

86-
public static class NotificationWorker extends ListenableWorker {
70+
public static class NotificationWorker extends Worker {
8771

8872
public NotificationWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
8973
super(context, workerParams);
9074
}
9175

9276
@NonNull
9377
@Override
94-
public ListenableFuture<Result> startWork() {
95-
return CallbackToFutureAdapter.getFuture(new CallbackToFutureAdapter.Resolver<Result>() {
96-
@Nullable
97-
@Override
98-
public Object attachCompleter(@NonNull CallbackToFutureAdapter.Completer<Result> completer) throws Exception {
99-
String notificationId = NotificationWorker.this.doWork(completer);
100-
101-
// This value is used only for debug purposes: it will be used
102-
// in toString() of returned future or error cases.
103-
return "NotificationWorkerFutureCallback_" + notificationId;
104-
}
105-
});
106-
}
107-
108-
private String doWork(@NonNull CallbackToFutureAdapter.Completer<Result> completer) {
78+
public Result doWork() {
10979
Data inputData = getInputData();
11080
try {
11181
OneSignal.onesignalLog(OneSignal.LOG_LEVEL.DEBUG, "NotificationWorker running doWork with data: " + inputData);
@@ -116,7 +86,6 @@ private String doWork(@NonNull CallbackToFutureAdapter.Completer<Result> complet
11686
boolean isRestoring = inputData.getBoolean(IS_RESTORING_WORKER_DATA_PARAM, false);
11787

11888
processNotificationData(
119-
completer,
12089
getApplicationContext(),
12190
androidNotificationId,
12291
jsonPayload,
@@ -125,36 +94,30 @@ private String doWork(@NonNull CallbackToFutureAdapter.Completer<Result> complet
12594
} catch (JSONException e) {
12695
OneSignal.onesignalLog(OneSignal.LOG_LEVEL.ERROR, "Error occurred doing work for job with id: " + getId().toString());
12796
e.printStackTrace();
128-
completer.setException(e);
97+
return Result.failure();
12998
}
130-
return inputData.getString(OS_NOTIFICATION_ID);
99+
return Result.success();
131100
}
132-
}
133101

134-
static void processNotificationData(Context context, int androidNotificationId, JSONObject jsonPayload,
135-
boolean isRestoring, Long timestamp) {
136-
processNotificationData(null, context, androidNotificationId, jsonPayload, isRestoring, timestamp);
137-
}
102+
private void processNotificationData(Context context, int androidNotificationId, JSONObject jsonPayload,
103+
boolean isRestoring, Long timestamp) {
104+
OSNotification notification = new OSNotification(null, jsonPayload, androidNotificationId);
105+
OSNotificationController controller = new OSNotificationController(context, notification, jsonPayload, isRestoring, true, timestamp);
106+
OSNotificationReceivedEvent notificationReceived = new OSNotificationReceivedEvent(controller, notification);
138107

139-
static void processNotificationData(CallbackToFutureAdapter.Completer<ListenableWorker.Result> completer,
140-
Context context, int androidNotificationId, JSONObject jsonPayload,
141-
boolean isRestoring, Long timestamp) {
142-
OSNotification notification = new OSNotification(null, jsonPayload, androidNotificationId);
143-
OSNotificationController controller = new OSNotificationController(completer, context, notification, jsonPayload, isRestoring, true, timestamp);
144-
OSNotificationReceivedEvent notificationReceived = new OSNotificationReceivedEvent(controller, notification);
108+
if (OneSignal.remoteNotificationReceivedHandler != null)
109+
try {
110+
OneSignal.remoteNotificationReceivedHandler.remoteNotificationReceived(context, notificationReceived);
111+
} catch (Throwable t) {
112+
OneSignal.Log(OneSignal.LOG_LEVEL.ERROR, "remoteNotificationReceived throw an exception. Displaying normal OneSignal notification.", t);
113+
notificationReceived.complete(notification);
145114

146-
if (OneSignal.remoteNotificationReceivedHandler != null)
147-
try {
148-
OneSignal.remoteNotificationReceivedHandler.remoteNotificationReceived(context, notificationReceived);
149-
} catch (Throwable t) {
150-
OneSignal.Log(OneSignal.LOG_LEVEL.ERROR, "remoteNotificationReceived throw an exception. Displaying normal OneSignal notification.", t);
115+
throw t;
116+
}
117+
else {
118+
OneSignal.Log(OneSignal.LOG_LEVEL.WARN, "remoteNotificationReceivedHandler not setup, displaying normal OneSignal notification");
151119
notificationReceived.complete(notification);
152-
153-
throw t;
154120
}
155-
else {
156-
OneSignal.Log(OneSignal.LOG_LEVEL.WARN, "remoteNotificationReceivedHandler not setup, displaying normal OneSignal notification");
157-
notificationReceived.complete(notification);
158121
}
159122
}
160123
}

0 commit comments

Comments
 (0)