@ammarahmed/notifee-react-native 7.3.1 → 7.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/android/build.gradle +36 -18
- package/android/schemas/app.notifee.core.database.NotifeeCoreDatabase/1.json +46 -0
- package/android/schemas/app.notifee.core.database.NotifeeCoreDatabase/2.json +53 -0
- package/android/src/main/java/app/notifee/core/AlarmPermissionBroadcastReceiver.java +19 -0
- package/android/src/main/java/app/notifee/core/BlockStateBroadcastReceiver.java +164 -0
- package/android/src/main/java/app/notifee/core/ChannelManager.java +351 -0
- package/android/src/main/java/app/notifee/core/ContextHolder.java +33 -0
- package/android/src/main/java/app/notifee/core/EventBus.java +63 -0
- package/android/src/main/java/app/notifee/core/EventSubscriber.java +82 -0
- package/android/src/main/java/app/notifee/core/ForegroundService.java +125 -0
- package/android/src/main/java/app/notifee/core/InitProvider.java +92 -0
- package/android/src/main/java/app/notifee/core/KeepForSdk.java +26 -0
- package/android/src/main/java/app/notifee/core/Logger.java +68 -0
- package/android/src/main/java/app/notifee/core/Notifee.java +533 -0
- package/android/src/main/java/app/notifee/core/NotifeeAlarmManager.java +256 -0
- package/android/src/main/java/app/notifee/core/NotificationAlarmReceiver.java +32 -0
- package/android/src/main/java/app/notifee/core/NotificationManager.java +903 -0
- package/android/src/main/java/app/notifee/core/NotificationPendingIntent.java +189 -0
- package/android/src/main/java/app/notifee/core/NotificationReceiverActivity.java +38 -0
- package/android/src/main/java/app/notifee/core/NotificationReceiverHandler.java +140 -0
- package/android/src/main/java/app/notifee/core/Preferences.java +79 -0
- package/android/src/main/java/app/notifee/core/RebootBroadcastReceiver.java +38 -0
- package/android/src/main/java/app/notifee/core/ReceiverService.java +268 -0
- package/android/src/main/java/app/notifee/core/Worker.java +87 -0
- package/android/src/main/java/app/notifee/core/database/NotifeeCoreDatabase.java +76 -0
- package/android/src/main/java/app/notifee/core/database/WorkDataDao.java +52 -0
- package/android/src/main/java/app/notifee/core/database/WorkDataEntity.java +68 -0
- package/android/src/main/java/app/notifee/core/database/WorkDataRepository.java +107 -0
- package/android/src/main/java/app/notifee/core/event/BlockStateEvent.java +102 -0
- package/android/src/main/java/app/notifee/core/event/ForegroundServiceEvent.java +48 -0
- package/android/src/main/java/app/notifee/core/event/InitialNotificationEvent.java +50 -0
- package/android/src/main/java/app/notifee/core/event/LogEvent.java +74 -0
- package/android/src/main/java/app/notifee/core/event/MainComponentEvent.java +33 -0
- package/android/src/main/java/app/notifee/core/event/NotificationEvent.java +97 -0
- package/android/src/main/java/app/notifee/core/interfaces/EventListener.java +39 -0
- package/android/src/main/java/app/notifee/core/interfaces/MethodCallResult.java +27 -0
- package/android/src/main/java/app/notifee/core/model/ChannelGroupModel.java +48 -0
- package/android/src/main/java/app/notifee/core/model/ChannelModel.java +123 -0
- package/android/src/main/java/app/notifee/core/model/IntervalTriggerModel.java +63 -0
- package/android/src/main/java/app/notifee/core/model/NotificationAndroidActionModel.java +125 -0
- package/android/src/main/java/app/notifee/core/model/NotificationAndroidModel.java +654 -0
- package/android/src/main/java/app/notifee/core/model/NotificationAndroidPressActionModel.java +146 -0
- package/android/src/main/java/app/notifee/core/model/NotificationAndroidStyleModel.java +341 -0
- package/android/src/main/java/app/notifee/core/model/NotificationModel.java +72 -0
- package/android/src/main/java/app/notifee/core/model/TimestampTriggerModel.java +163 -0
- package/android/src/main/java/app/notifee/core/model/package-info.java +4 -0
- package/android/src/main/java/app/notifee/core/utility/AlarmUtils.java +52 -0
- package/android/src/main/java/app/notifee/core/utility/Callbackable.java +12 -0
- package/android/src/main/java/app/notifee/core/utility/ColorUtils.java +62 -0
- package/android/src/main/java/app/notifee/core/utility/ExtendedListenableFuture.java +84 -0
- package/android/src/main/java/app/notifee/core/utility/IntentUtils.java +136 -0
- package/android/src/main/java/app/notifee/core/utility/ObjectUtils.java +187 -0
- package/android/src/main/java/app/notifee/core/utility/PowerManagerUtils.java +334 -0
- package/android/src/main/java/app/notifee/core/utility/ResourceUtils.java +309 -0
- package/android/src/main/java/app/notifee/core/utility/TextUtils.java +28 -0
- package/android/src/main/java/app/notifee/core/utility/package-info.java +4 -0
- package/dist/types/Notification.d.ts +8 -1
- package/dist/types/Notification.js +6 -0
- package/dist/types/Notification.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/jest-mock.js +7 -4
- package/package.json +1 -3
- package/src/types/Notification.ts +8 -0
- package/src/version.ts +1 -1
- package/android/libs/app/notifee/core/202108261756/core-202108261756.aar +0 -0
- package/android/libs/app/notifee/core/202108261756/core-202108261756.aar.md5 +0 -1
- package/android/libs/app/notifee/core/202108261756/core-202108261756.aar.sha1 +0 -1
- package/android/libs/app/notifee/core/202108261756/core-202108261756.aar.sha256 +0 -1
- package/android/libs/app/notifee/core/202108261756/core-202108261756.aar.sha512 +0 -1
- package/android/libs/app/notifee/core/202108261756/core-202108261756.pom +0 -9
- package/android/libs/app/notifee/core/202108261756/core-202108261756.pom.md5 +0 -1
- package/android/libs/app/notifee/core/202108261756/core-202108261756.pom.sha1 +0 -1
- package/android/libs/app/notifee/core/202108261756/core-202108261756.pom.sha256 +0 -1
- package/android/libs/app/notifee/core/202108261756/core-202108261756.pom.sha512 +0 -1
- package/android/libs/app/notifee/core/maven-metadata.xml +0 -13
- package/android/libs/app/notifee/core/maven-metadata.xml.md5 +0 -1
- package/android/libs/app/notifee/core/maven-metadata.xml.sha1 +0 -1
- package/android/libs/app/notifee/core/maven-metadata.xml.sha256 +0 -1
- package/android/libs/app/notifee/core/maven-metadata.xml.sha512 +0 -1
|
@@ -0,0 +1,903 @@
|
|
|
1
|
+
package app.notifee.core;
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* Copyright (c) 2016-present Invertase Limited & Contributors
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this library except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import static app.notifee.core.ContextHolder.getApplicationContext;
|
|
21
|
+
import static app.notifee.core.ReceiverService.ACTION_PRESS_INTENT;
|
|
22
|
+
import static app.notifee.core.event.NotificationEvent.TYPE_ACTION_PRESS;
|
|
23
|
+
import static app.notifee.core.event.NotificationEvent.TYPE_PRESS;
|
|
24
|
+
import static java.lang.Integer.parseInt;
|
|
25
|
+
|
|
26
|
+
import android.app.Notification;
|
|
27
|
+
import android.app.PendingIntent;
|
|
28
|
+
import android.content.Context;
|
|
29
|
+
import android.content.Intent;
|
|
30
|
+
import android.graphics.Bitmap;
|
|
31
|
+
import android.net.Uri;
|
|
32
|
+
import android.os.Build;
|
|
33
|
+
import android.os.Bundle;
|
|
34
|
+
import android.service.notification.StatusBarNotification;
|
|
35
|
+
import androidx.annotation.NonNull;
|
|
36
|
+
import androidx.concurrent.futures.CallbackToFutureAdapter;
|
|
37
|
+
import androidx.core.app.NotificationCompat;
|
|
38
|
+
import androidx.core.app.NotificationManagerCompat;
|
|
39
|
+
import androidx.core.app.RemoteInput;
|
|
40
|
+
import androidx.core.graphics.drawable.IconCompat;
|
|
41
|
+
import androidx.work.Data;
|
|
42
|
+
import androidx.work.ExistingPeriodicWorkPolicy;
|
|
43
|
+
import androidx.work.ExistingWorkPolicy;
|
|
44
|
+
import androidx.work.ListenableWorker;
|
|
45
|
+
import androidx.work.ListenableWorker.Result;
|
|
46
|
+
import androidx.work.OneTimeWorkRequest;
|
|
47
|
+
import androidx.work.PeriodicWorkRequest;
|
|
48
|
+
import androidx.work.WorkManager;
|
|
49
|
+
import app.notifee.core.database.WorkDataEntity;
|
|
50
|
+
import app.notifee.core.database.WorkDataRepository;
|
|
51
|
+
import app.notifee.core.event.MainComponentEvent;
|
|
52
|
+
import app.notifee.core.event.NotificationEvent;
|
|
53
|
+
import app.notifee.core.interfaces.MethodCallResult;
|
|
54
|
+
import app.notifee.core.model.IntervalTriggerModel;
|
|
55
|
+
import app.notifee.core.model.NotificationAndroidActionModel;
|
|
56
|
+
import app.notifee.core.model.NotificationAndroidModel;
|
|
57
|
+
import app.notifee.core.model.NotificationAndroidPressActionModel;
|
|
58
|
+
import app.notifee.core.model.NotificationAndroidStyleModel;
|
|
59
|
+
import app.notifee.core.model.NotificationModel;
|
|
60
|
+
import app.notifee.core.model.TimestampTriggerModel;
|
|
61
|
+
import app.notifee.core.utility.Callbackable;
|
|
62
|
+
import app.notifee.core.utility.ExtendedListenableFuture;
|
|
63
|
+
import app.notifee.core.utility.IntentUtils;
|
|
64
|
+
import app.notifee.core.utility.ObjectUtils;
|
|
65
|
+
import app.notifee.core.utility.PowerManagerUtils;
|
|
66
|
+
import app.notifee.core.utility.ResourceUtils;
|
|
67
|
+
import app.notifee.core.utility.TextUtils;
|
|
68
|
+
import com.google.common.util.concurrent.AsyncFunction;
|
|
69
|
+
import com.google.common.util.concurrent.FutureCallback;
|
|
70
|
+
import com.google.common.util.concurrent.Futures;
|
|
71
|
+
import com.google.common.util.concurrent.ListenableFuture;
|
|
72
|
+
import com.google.common.util.concurrent.ListeningExecutorService;
|
|
73
|
+
import com.google.common.util.concurrent.MoreExecutors;
|
|
74
|
+
import java.util.ArrayList;
|
|
75
|
+
import java.util.List;
|
|
76
|
+
import java.util.Objects;
|
|
77
|
+
import java.util.concurrent.Callable;
|
|
78
|
+
import java.util.concurrent.ExecutorService;
|
|
79
|
+
import java.util.concurrent.Executors;
|
|
80
|
+
import java.util.concurrent.TimeUnit;
|
|
81
|
+
import java.util.concurrent.TimeoutException;
|
|
82
|
+
|
|
83
|
+
class NotificationManager {
|
|
84
|
+
private static final String TAG = "NotificationManager";
|
|
85
|
+
private static final String EXTRA_NOTIFEE_NOTIFICATION = "notifee.notification";
|
|
86
|
+
private static final String EXTRA_NOTIFEE_TRIGGER = "notifee.trigger";
|
|
87
|
+
private static final ExecutorService CACHED_THREAD_POOL = Executors.newCachedThreadPool();
|
|
88
|
+
private static final ListeningExecutorService LISTENING_CACHED_THREAD_POOL = MoreExecutors.listeningDecorator(
|
|
89
|
+
CACHED_THREAD_POOL);
|
|
90
|
+
private static final int NOTIFICATION_TYPE_ALL = 0;
|
|
91
|
+
private static final int NOTIFICATION_TYPE_DISPLAYED = 1;
|
|
92
|
+
private static final int NOTIFICATION_TYPE_TRIGGER = 2;
|
|
93
|
+
|
|
94
|
+
private static ListenableFuture<NotificationCompat.Builder> notificationBundleToBuilder(
|
|
95
|
+
NotificationModel notificationModel) {
|
|
96
|
+
final NotificationAndroidModel androidModel = notificationModel.getAndroid();
|
|
97
|
+
|
|
98
|
+
/*
|
|
99
|
+
* Construct the initial NotificationCompat.Builder instance
|
|
100
|
+
*/
|
|
101
|
+
Callable<NotificationCompat.Builder> builderCallable =
|
|
102
|
+
() -> {
|
|
103
|
+
Boolean hasCustomSound = false;
|
|
104
|
+
NotificationCompat.Builder builder =
|
|
105
|
+
new NotificationCompat.Builder(getApplicationContext(), androidModel.getChannelId());
|
|
106
|
+
|
|
107
|
+
// must always keep at top
|
|
108
|
+
builder.setExtras(notificationModel.getData());
|
|
109
|
+
|
|
110
|
+
builder.setDeleteIntent(
|
|
111
|
+
ReceiverService.createIntent(
|
|
112
|
+
ReceiverService.DELETE_INTENT,
|
|
113
|
+
new String[] {"notification"},
|
|
114
|
+
notificationModel.toBundle()));
|
|
115
|
+
int targetSdkVersion =
|
|
116
|
+
ContextHolder.getApplicationContext().getApplicationInfo().targetSdkVersion;
|
|
117
|
+
if (targetSdkVersion >= Build.VERSION_CODES.S
|
|
118
|
+
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
119
|
+
builder.setContentIntent(
|
|
120
|
+
NotificationPendingIntent.createIntent(
|
|
121
|
+
notificationModel.getHashCode(),
|
|
122
|
+
androidModel.getPressAction(),
|
|
123
|
+
TYPE_PRESS,
|
|
124
|
+
new String[] {"notification", "pressAction"},
|
|
125
|
+
notificationModel.toBundle(),
|
|
126
|
+
androidModel.getPressAction()));
|
|
127
|
+
} else {
|
|
128
|
+
builder.setContentIntent(
|
|
129
|
+
ReceiverService.createIntent(
|
|
130
|
+
ReceiverService.PRESS_INTENT,
|
|
131
|
+
new String[] {"notification", "pressAction"},
|
|
132
|
+
notificationModel.toBundle(),
|
|
133
|
+
androidModel.getPressAction()));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (notificationModel.getTitle() != null) {
|
|
137
|
+
builder.setContentTitle(TextUtils.fromHtml(notificationModel.getTitle()));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (notificationModel.getSubTitle() != null) {
|
|
141
|
+
builder.setSubText(TextUtils.fromHtml(notificationModel.getSubTitle()));
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (notificationModel.getBody() != null) {
|
|
145
|
+
builder.setContentText(TextUtils.fromHtml(notificationModel.getBody()));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (androidModel.getBadgeIconType() != null) {
|
|
149
|
+
builder.setBadgeIconType(androidModel.getBadgeIconType());
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (androidModel.getCategory() != null) {
|
|
153
|
+
builder.setCategory(androidModel.getCategory());
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (androidModel.getColor() != null) {
|
|
157
|
+
builder.setColor(androidModel.getColor());
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
builder.setColorized(androidModel.getColorized());
|
|
161
|
+
|
|
162
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
163
|
+
builder.setChronometerCountDown(androidModel.getChronometerCountDown());
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (androidModel.getGroup() != null) {
|
|
167
|
+
builder.setGroup(androidModel.getGroup());
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
builder.setGroupAlertBehavior(androidModel.getGroupAlertBehaviour());
|
|
171
|
+
builder.setGroupSummary(androidModel.getGroupSummary());
|
|
172
|
+
|
|
173
|
+
if (androidModel.getInputHistory() != null) {
|
|
174
|
+
builder.setRemoteInputHistory(androidModel.getInputHistory());
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (androidModel.getLights() != null) {
|
|
178
|
+
ArrayList<Integer> lights = androidModel.getLights();
|
|
179
|
+
builder.setLights(lights.get(0), lights.get(1), lights.get(2));
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
builder.setLocalOnly(androidModel.getLocalOnly());
|
|
183
|
+
|
|
184
|
+
if (androidModel.getNumber() != null) {
|
|
185
|
+
builder.setNumber(androidModel.getNumber());
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (androidModel.getSound() != null) {
|
|
189
|
+
Uri soundUri = ResourceUtils.getSoundUri(androidModel.getSound());
|
|
190
|
+
if (soundUri != null) {
|
|
191
|
+
hasCustomSound = true;
|
|
192
|
+
builder.setSound(soundUri);
|
|
193
|
+
} else {
|
|
194
|
+
Logger.w(
|
|
195
|
+
TAG,
|
|
196
|
+
"Unable to retrieve sound for notification, sound was specified as: "
|
|
197
|
+
+ androidModel.getSound());
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
builder.setDefaults(androidModel.getDefaults(hasCustomSound));
|
|
202
|
+
builder.setOngoing(androidModel.getOngoing());
|
|
203
|
+
builder.setOnlyAlertOnce(androidModel.getOnlyAlertOnce());
|
|
204
|
+
builder.setPriority(androidModel.getPriority());
|
|
205
|
+
|
|
206
|
+
NotificationAndroidModel.AndroidProgress progress = androidModel.getProgress();
|
|
207
|
+
if (progress != null) {
|
|
208
|
+
builder.setProgress(
|
|
209
|
+
progress.getMax(), progress.getCurrent(), progress.getIndeterminate());
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
if (androidModel.getShortcutId() != null) {
|
|
213
|
+
builder.setShortcutId(androidModel.getShortcutId());
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
builder.setShowWhen(androidModel.getShowTimestamp());
|
|
217
|
+
|
|
218
|
+
Integer smallIconId = androidModel.getSmallIcon();
|
|
219
|
+
if (smallIconId != null) {
|
|
220
|
+
Integer smallIconLevel = androidModel.getSmallIconLevel();
|
|
221
|
+
if (smallIconLevel != null) {
|
|
222
|
+
builder.setSmallIcon(smallIconId, smallIconLevel);
|
|
223
|
+
} else {
|
|
224
|
+
builder.setSmallIcon(smallIconId);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (androidModel.getSortKey() != null) {
|
|
229
|
+
builder.setSortKey(androidModel.getSortKey());
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (androidModel.getTicker() != null) {
|
|
233
|
+
builder.setTicker(androidModel.getTicker());
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
if (androidModel.getTimeoutAfter() != null) {
|
|
237
|
+
builder.setTimeoutAfter(androidModel.getTimeoutAfter());
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
builder.setUsesChronometer(androidModel.getShowChronometer());
|
|
241
|
+
|
|
242
|
+
long[] vibrationPattern = androidModel.getVibrationPattern();
|
|
243
|
+
if (vibrationPattern.length > 0) builder.setVibrate(vibrationPattern);
|
|
244
|
+
|
|
245
|
+
builder.setVisibility(androidModel.getVisibility());
|
|
246
|
+
|
|
247
|
+
long timestamp = androidModel.getTimestamp();
|
|
248
|
+
if (timestamp > -1) builder.setWhen(timestamp);
|
|
249
|
+
|
|
250
|
+
builder.setAutoCancel(androidModel.getAutoCancel());
|
|
251
|
+
|
|
252
|
+
return builder;
|
|
253
|
+
};
|
|
254
|
+
|
|
255
|
+
/*
|
|
256
|
+
* A task continuation that fetches the largeIcon through Fresco, if specified.
|
|
257
|
+
*/
|
|
258
|
+
AsyncFunction<NotificationCompat.Builder, NotificationCompat.Builder> largeIconContinuation =
|
|
259
|
+
taskResult -> LISTENING_CACHED_THREAD_POOL.submit(() -> {
|
|
260
|
+
NotificationCompat.Builder builder = taskResult;
|
|
261
|
+
|
|
262
|
+
if (androidModel.hasLargeIcon()) {
|
|
263
|
+
String largeIcon = androidModel.getLargeIcon();
|
|
264
|
+
Bitmap largeIconBitmap = null;
|
|
265
|
+
|
|
266
|
+
try {
|
|
267
|
+
largeIconBitmap = ResourceUtils.getImageBitmapFromUrl(largeIcon)
|
|
268
|
+
.get(10, TimeUnit.SECONDS);
|
|
269
|
+
} catch (TimeoutException e) {
|
|
270
|
+
Logger.e(
|
|
271
|
+
TAG,
|
|
272
|
+
"Timeout occurred whilst trying to retrieve a largeIcon image: " + largeIcon,
|
|
273
|
+
e);
|
|
274
|
+
} catch (Exception e) {
|
|
275
|
+
Logger.e(
|
|
276
|
+
TAG,
|
|
277
|
+
"An error occurred whilst trying to retrieve a largeIcon image: " + largeIcon,
|
|
278
|
+
e);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (largeIconBitmap != null) {
|
|
282
|
+
if (androidModel.getCircularLargeIcon()) {
|
|
283
|
+
largeIconBitmap = ResourceUtils.getCircularBitmap(largeIconBitmap);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
builder.setLargeIcon(largeIconBitmap);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
return builder;
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
/*
|
|
294
|
+
* A task continuation for full-screen action, if specified.
|
|
295
|
+
*/
|
|
296
|
+
AsyncFunction<NotificationCompat.Builder, NotificationCompat.Builder>
|
|
297
|
+
fullScreenActionContinuation =
|
|
298
|
+
taskResult -> LISTENING_CACHED_THREAD_POOL.submit(() -> {
|
|
299
|
+
NotificationCompat.Builder builder = taskResult;
|
|
300
|
+
if (androidModel.hasFullScreenAction()) {
|
|
301
|
+
NotificationAndroidPressActionModel fullScreenActionBundle =
|
|
302
|
+
androidModel.getFullScreenAction();
|
|
303
|
+
|
|
304
|
+
String launchActivity = fullScreenActionBundle.getLaunchActivity();
|
|
305
|
+
Class launchActivityClass = IntentUtils.getLaunchActivity(launchActivity);
|
|
306
|
+
if (launchActivityClass == null) {
|
|
307
|
+
Logger.e(
|
|
308
|
+
TAG,
|
|
309
|
+
String.format(
|
|
310
|
+
"Launch Activity for full-screen action does not exist ('%s').",
|
|
311
|
+
launchActivity));
|
|
312
|
+
return builder;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
Intent launchIntent = new Intent(getApplicationContext(), launchActivityClass);
|
|
316
|
+
if (fullScreenActionBundle.getLaunchActivityFlags() != -1) {
|
|
317
|
+
launchIntent.addFlags(fullScreenActionBundle.getLaunchActivityFlags());
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (fullScreenActionBundle.getMainComponent() != null) {
|
|
321
|
+
launchIntent.putExtra("mainComponent", fullScreenActionBundle.getMainComponent());
|
|
322
|
+
launchIntent.putExtra("notification", notificationModel.toBundle());
|
|
323
|
+
EventBus.postSticky(
|
|
324
|
+
new MainComponentEvent(fullScreenActionBundle.getMainComponent()));
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
PendingIntent fullScreenPendingIntent =
|
|
328
|
+
PendingIntent.getActivity(
|
|
329
|
+
getApplicationContext(),
|
|
330
|
+
notificationModel.getHashCode(),
|
|
331
|
+
launchIntent,
|
|
332
|
+
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
|
|
333
|
+
builder.setFullScreenIntent(fullScreenPendingIntent, true);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
return builder;
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
/*
|
|
340
|
+
* A task continuation that builds all actions, if any. Additionally fetches
|
|
341
|
+
* icon bitmaps through Fresco.
|
|
342
|
+
*/
|
|
343
|
+
AsyncFunction<NotificationCompat.Builder, NotificationCompat.Builder> actionsContinuation =
|
|
344
|
+
taskResult -> LISTENING_CACHED_THREAD_POOL.submit(() -> {
|
|
345
|
+
NotificationCompat.Builder builder = taskResult;
|
|
346
|
+
ArrayList<NotificationAndroidActionModel> actionBundles = androidModel.getActions();
|
|
347
|
+
|
|
348
|
+
if (actionBundles == null) {
|
|
349
|
+
return builder;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
for (NotificationAndroidActionModel actionBundle : actionBundles) {
|
|
353
|
+
PendingIntent pendingIntent = null;
|
|
354
|
+
int targetSdkVersion =
|
|
355
|
+
ContextHolder.getApplicationContext().getApplicationInfo().targetSdkVersion;
|
|
356
|
+
if (targetSdkVersion >= Build.VERSION_CODES.S
|
|
357
|
+
&& Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
|
358
|
+
pendingIntent =
|
|
359
|
+
NotificationPendingIntent.createIntent(
|
|
360
|
+
notificationModel.getHashCode(),
|
|
361
|
+
actionBundle.getPressAction().toBundle(),
|
|
362
|
+
TYPE_ACTION_PRESS,
|
|
363
|
+
new String[] {"notification", "pressAction"},
|
|
364
|
+
notificationModel.toBundle(),
|
|
365
|
+
actionBundle.getPressAction().toBundle());
|
|
366
|
+
} else {
|
|
367
|
+
pendingIntent =
|
|
368
|
+
ReceiverService.createIntent(
|
|
369
|
+
ACTION_PRESS_INTENT,
|
|
370
|
+
new String[] {"notification", "pressAction"},
|
|
371
|
+
notificationModel.toBundle(),
|
|
372
|
+
actionBundle.getPressAction().toBundle());
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
String icon = actionBundle.getIcon();
|
|
376
|
+
Bitmap iconBitmap = null;
|
|
377
|
+
|
|
378
|
+
if (icon != null) {
|
|
379
|
+
try {
|
|
380
|
+
iconBitmap =
|
|
381
|
+
ResourceUtils.getImageBitmapFromUrl(actionBundle.getIcon())
|
|
382
|
+
.get(10, TimeUnit.SECONDS);
|
|
383
|
+
} catch (TimeoutException e) {
|
|
384
|
+
Logger.e(
|
|
385
|
+
TAG, "Timeout occurred whilst trying to retrieve an action icon: " + icon, e);
|
|
386
|
+
} catch (Exception e) {
|
|
387
|
+
Logger.e(
|
|
388
|
+
TAG, "An error occurred whilst trying to retrieve an action icon: " + icon, e);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
IconCompat iconCompat = null;
|
|
393
|
+
if (iconBitmap != null) {
|
|
394
|
+
iconCompat = IconCompat.createWithAdaptiveBitmap(iconBitmap);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
NotificationCompat.Action.Builder actionBuilder =
|
|
398
|
+
new NotificationCompat.Action.Builder(
|
|
399
|
+
iconCompat, TextUtils.fromHtml(actionBundle.getTitle()), pendingIntent);
|
|
400
|
+
|
|
401
|
+
RemoteInput remoteInput = actionBundle.getRemoteInput(actionBuilder);
|
|
402
|
+
if (remoteInput != null) {
|
|
403
|
+
actionBuilder.addRemoteInput(remoteInput);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
builder.addAction(actionBuilder.build());
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
return builder;
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
/*
|
|
413
|
+
* A task continuation that builds the notification style, if any. Additionally
|
|
414
|
+
* fetches any image bitmaps (e.g. Person image, or BigPicture image) through
|
|
415
|
+
* Fresco.
|
|
416
|
+
*/
|
|
417
|
+
AsyncFunction<NotificationCompat.Builder, NotificationCompat.Builder> styleContinuation =
|
|
418
|
+
builder -> LISTENING_CACHED_THREAD_POOL.submit(() -> {
|
|
419
|
+
NotificationAndroidStyleModel androidStyleBundle = androidModel.getStyle();
|
|
420
|
+
if (androidStyleBundle == null) {
|
|
421
|
+
return builder;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
ListenableFuture<NotificationCompat.Style> styleTask =
|
|
425
|
+
androidStyleBundle.getStyleTask(LISTENING_CACHED_THREAD_POOL);
|
|
426
|
+
if (styleTask == null) {
|
|
427
|
+
return builder;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
NotificationCompat.Style style = styleTask.get();
|
|
431
|
+
if (style != null) {
|
|
432
|
+
builder.setStyle(style);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
return builder;
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
return new ExtendedListenableFuture<>(
|
|
439
|
+
LISTENING_CACHED_THREAD_POOL.submit(builderCallable))
|
|
440
|
+
// get a large image bitmap if largeIcon is set
|
|
441
|
+
.continueWith(largeIconContinuation, LISTENING_CACHED_THREAD_POOL)
|
|
442
|
+
// build notification actions, tasks based to allow image fetching
|
|
443
|
+
.continueWith(actionsContinuation, LISTENING_CACHED_THREAD_POOL)
|
|
444
|
+
// build notification style, tasks based to allow image fetching
|
|
445
|
+
.continueWith(styleContinuation, LISTENING_CACHED_THREAD_POOL)
|
|
446
|
+
// set full screen action, if fullScreenAction is set
|
|
447
|
+
.continueWith(fullScreenActionContinuation, LISTENING_CACHED_THREAD_POOL);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
static ListenableFuture<Void> cancelAllNotifications(@NonNull int notificationType) {
|
|
451
|
+
return new ExtendedListenableFuture<>(LISTENING_CACHED_THREAD_POOL.submit(
|
|
452
|
+
() -> {
|
|
453
|
+
NotificationManagerCompat notificationManagerCompat =
|
|
454
|
+
NotificationManagerCompat.from(getApplicationContext());
|
|
455
|
+
|
|
456
|
+
if (notificationType == NOTIFICATION_TYPE_DISPLAYED
|
|
457
|
+
|| notificationType == NOTIFICATION_TYPE_ALL) {
|
|
458
|
+
notificationManagerCompat.cancelAll();
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
if (notificationType == NOTIFICATION_TYPE_TRIGGER
|
|
462
|
+
|| notificationType == NOTIFICATION_TYPE_ALL) {
|
|
463
|
+
WorkManager workManager = WorkManager.getInstance(getApplicationContext());
|
|
464
|
+
workManager.cancelAllWorkByTag(Worker.WORK_TYPE_NOTIFICATION_TRIGGER);
|
|
465
|
+
|
|
466
|
+
// Remove all cancelled and finished work from its internal database
|
|
467
|
+
// states include SUCCEEDED, FAILED and CANCELLED
|
|
468
|
+
workManager.pruneWork();
|
|
469
|
+
}
|
|
470
|
+
return null;
|
|
471
|
+
}))
|
|
472
|
+
.continueWith(task -> {
|
|
473
|
+
if (notificationType == NOTIFICATION_TYPE_TRIGGER
|
|
474
|
+
|| notificationType == NOTIFICATION_TYPE_ALL) {
|
|
475
|
+
return new ExtendedListenableFuture<Void>(NotifeeAlarmManager.cancelAllNotifications())
|
|
476
|
+
.addOnCompleteListener((e, result) -> {
|
|
477
|
+
if (e == null) {
|
|
478
|
+
WorkDataRepository.getInstance(getApplicationContext())
|
|
479
|
+
.deleteAll();
|
|
480
|
+
}
|
|
481
|
+
}, LISTENING_CACHED_THREAD_POOL);
|
|
482
|
+
}
|
|
483
|
+
return Futures.immediateFuture(null);
|
|
484
|
+
}, LISTENING_CACHED_THREAD_POOL);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
static ListenableFuture<Void> cancelAllNotificationsWithIds(
|
|
488
|
+
@NonNull int notificationType, @NonNull List<String> ids, String tag) {
|
|
489
|
+
return new ExtendedListenableFuture<>(LISTENING_CACHED_THREAD_POOL.submit(
|
|
490
|
+
() -> {
|
|
491
|
+
WorkManager workManager = WorkManager.getInstance(getApplicationContext());
|
|
492
|
+
NotificationManagerCompat notificationManagerCompat =
|
|
493
|
+
NotificationManagerCompat.from(getApplicationContext());
|
|
494
|
+
|
|
495
|
+
for (String id : ids) {
|
|
496
|
+
Logger.i(TAG, "Removing notification with id " + id);
|
|
497
|
+
|
|
498
|
+
if (notificationType != NOTIFICATION_TYPE_TRIGGER) {
|
|
499
|
+
// Cancel notifications displayed by FCM which will always have
|
|
500
|
+
// an id of 0 and a tag, see https://github.com/invertase/notifee/pull/175
|
|
501
|
+
if (tag != null && id.equals("0")) {
|
|
502
|
+
// Attempt to parse id as integer
|
|
503
|
+
Integer integerId = null;
|
|
504
|
+
|
|
505
|
+
try {
|
|
506
|
+
integerId = parseInt(id);
|
|
507
|
+
} catch (Exception e) {
|
|
508
|
+
Logger.e(
|
|
509
|
+
TAG,
|
|
510
|
+
"cancelAllNotificationsWithIds -> Failed to parse id as integer " + id);
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
if (integerId != null) {
|
|
514
|
+
notificationManagerCompat.cancel(tag, integerId);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// Cancel a notification created with notifee
|
|
519
|
+
notificationManagerCompat.cancel(tag, id.hashCode());
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
if (notificationType != NOTIFICATION_TYPE_DISPLAYED) {
|
|
523
|
+
Logger.i(TAG, "Removing notification with id " + id);
|
|
524
|
+
|
|
525
|
+
workManager.cancelUniqueWork("trigger:" + id);
|
|
526
|
+
// Remove all cancelled and finished work from its internal database
|
|
527
|
+
// states include SUCCEEDED, FAILED and CANCELLED
|
|
528
|
+
workManager.pruneWork();
|
|
529
|
+
|
|
530
|
+
// And with alarm manager
|
|
531
|
+
NotifeeAlarmManager.cancelNotification(id);
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
return null;
|
|
536
|
+
}))
|
|
537
|
+
.continueWith(
|
|
538
|
+
task -> {
|
|
539
|
+
// delete all from database
|
|
540
|
+
if (notificationType != NOTIFICATION_TYPE_DISPLAYED) {
|
|
541
|
+
WorkDataRepository.getInstance(getApplicationContext()).deleteByIds(ids);
|
|
542
|
+
}
|
|
543
|
+
return Futures.immediateFuture(null);
|
|
544
|
+
}, LISTENING_CACHED_THREAD_POOL);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
static ListenableFuture<Void> displayNotification(NotificationModel notificationModel, Bundle triggerBundle) {
|
|
548
|
+
return new ExtendedListenableFuture<>(notificationBundleToBuilder(notificationModel))
|
|
549
|
+
.continueWith(
|
|
550
|
+
(taskResult) -> {
|
|
551
|
+
NotificationCompat.Builder builder = taskResult;
|
|
552
|
+
|
|
553
|
+
// Add the following extras for `getDisplayedNotifications()`
|
|
554
|
+
Bundle extrasBundle = new Bundle();
|
|
555
|
+
extrasBundle.putBundle(EXTRA_NOTIFEE_NOTIFICATION, notificationModel.toBundle());
|
|
556
|
+
if (triggerBundle != null) {
|
|
557
|
+
extrasBundle.putBundle(EXTRA_NOTIFEE_TRIGGER, triggerBundle);
|
|
558
|
+
}
|
|
559
|
+
builder.addExtras(extrasBundle);
|
|
560
|
+
|
|
561
|
+
// build notification
|
|
562
|
+
Notification notification = Objects.requireNonNull(builder).build();
|
|
563
|
+
|
|
564
|
+
int hashCode = notificationModel.getHashCode();
|
|
565
|
+
|
|
566
|
+
NotificationAndroidModel androidBundle = notificationModel.getAndroid();
|
|
567
|
+
if (androidBundle.getLoopSound()) {
|
|
568
|
+
notification.flags |= Notification.FLAG_INSISTENT;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
if (androidBundle.getFlags() != null && androidBundle.getFlags().length > 0) {
|
|
572
|
+
for (int flag : androidBundle.getFlags()) {
|
|
573
|
+
notification.flags |= flag;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
if (androidBundle.getLightUpScreen()) {
|
|
578
|
+
PowerManagerUtils.lightUpScreenIfNeeded(ContextHolder.getApplicationContext());
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
if (androidBundle.getAsForegroundService()) {
|
|
582
|
+
ForegroundService.start(hashCode, notification, notificationModel.toBundle());
|
|
583
|
+
} else {
|
|
584
|
+
NotificationManagerCompat.from(getApplicationContext())
|
|
585
|
+
.notify(androidBundle.getTag(), hashCode, notification);
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
EventBus.post(
|
|
589
|
+
new NotificationEvent(NotificationEvent.TYPE_DELIVERED, notificationModel));
|
|
590
|
+
|
|
591
|
+
return Futures.immediateFuture(null);
|
|
592
|
+
}, CACHED_THREAD_POOL);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
static ListenableFuture<Void> createTriggerNotification(
|
|
596
|
+
NotificationModel notificationModel, Bundle triggerBundle) {
|
|
597
|
+
return
|
|
598
|
+
LISTENING_CACHED_THREAD_POOL.submit(
|
|
599
|
+
() -> {
|
|
600
|
+
int triggerType = ObjectUtils.getInt(triggerBundle.get("type"));
|
|
601
|
+
switch (triggerType) {
|
|
602
|
+
case 0:
|
|
603
|
+
createTimestampTriggerNotification(notificationModel, triggerBundle);
|
|
604
|
+
break;
|
|
605
|
+
case 1:
|
|
606
|
+
createIntervalTriggerNotification(notificationModel, triggerBundle);
|
|
607
|
+
break;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
EventBus.post(
|
|
611
|
+
new NotificationEvent(
|
|
612
|
+
NotificationEvent.TYPE_TRIGGER_NOTIFICATION_CREATED, notificationModel));
|
|
613
|
+
|
|
614
|
+
return null;
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
static void createIntervalTriggerNotification(
|
|
619
|
+
NotificationModel notificationModel, Bundle triggerBundle) {
|
|
620
|
+
IntervalTriggerModel trigger = IntervalTriggerModel.fromBundle(triggerBundle);
|
|
621
|
+
String uniqueWorkName = "trigger:" + notificationModel.getId();
|
|
622
|
+
WorkManager workManager = WorkManager.getInstance(getApplicationContext());
|
|
623
|
+
|
|
624
|
+
Data.Builder workDataBuilder =
|
|
625
|
+
new Data.Builder()
|
|
626
|
+
.putString(Worker.KEY_WORK_TYPE, Worker.WORK_TYPE_NOTIFICATION_TRIGGER)
|
|
627
|
+
.putString(Worker.KEY_WORK_REQUEST, Worker.WORK_REQUEST_PERIODIC)
|
|
628
|
+
.putString("id", notificationModel.getId());
|
|
629
|
+
|
|
630
|
+
WorkDataRepository.getInstance(getApplicationContext())
|
|
631
|
+
.insertTriggerNotification(notificationModel, triggerBundle, false);
|
|
632
|
+
|
|
633
|
+
long interval = trigger.getInterval();
|
|
634
|
+
|
|
635
|
+
PeriodicWorkRequest.Builder workRequestBuilder;
|
|
636
|
+
workRequestBuilder =
|
|
637
|
+
new PeriodicWorkRequest.Builder(Worker.class, interval, trigger.getTimeUnit());
|
|
638
|
+
|
|
639
|
+
workRequestBuilder.addTag(Worker.WORK_TYPE_NOTIFICATION_TRIGGER);
|
|
640
|
+
workRequestBuilder.addTag(uniqueWorkName);
|
|
641
|
+
workRequestBuilder.setInputData(workDataBuilder.build());
|
|
642
|
+
workManager.enqueueUniquePeriodicWork(
|
|
643
|
+
uniqueWorkName, ExistingPeriodicWorkPolicy.REPLACE, workRequestBuilder.build());
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
static void createTimestampTriggerNotification(
|
|
647
|
+
NotificationModel notificationModel, Bundle triggerBundle) {
|
|
648
|
+
TimestampTriggerModel trigger = TimestampTriggerModel.fromBundle(triggerBundle);
|
|
649
|
+
|
|
650
|
+
String uniqueWorkName = "trigger:" + notificationModel.getId();
|
|
651
|
+
|
|
652
|
+
long delay = trigger.getDelay();
|
|
653
|
+
int interval = trigger.getInterval();
|
|
654
|
+
|
|
655
|
+
// Save in DB
|
|
656
|
+
Data.Builder workDataBuilder =
|
|
657
|
+
new Data.Builder()
|
|
658
|
+
.putString(Worker.KEY_WORK_TYPE, Worker.WORK_TYPE_NOTIFICATION_TRIGGER)
|
|
659
|
+
.putString("id", notificationModel.getId());
|
|
660
|
+
|
|
661
|
+
Boolean withAlarmManager = trigger.getWithAlarmManager();
|
|
662
|
+
|
|
663
|
+
WorkDataRepository.getInstance(getApplicationContext())
|
|
664
|
+
.insertTriggerNotification(notificationModel, triggerBundle, withAlarmManager);
|
|
665
|
+
|
|
666
|
+
// Schedule notification with alarm manager
|
|
667
|
+
if (withAlarmManager) {
|
|
668
|
+
NotifeeAlarmManager.scheduleTimestampTriggerNotification(notificationModel, trigger);
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// Continue to schedule trigger notification with WorkManager
|
|
673
|
+
WorkManager workManager = WorkManager.getInstance(getApplicationContext());
|
|
674
|
+
|
|
675
|
+
// WorkManager - One time trigger
|
|
676
|
+
if (interval == -1) {
|
|
677
|
+
OneTimeWorkRequest.Builder workRequestBuilder = new OneTimeWorkRequest.Builder(Worker.class);
|
|
678
|
+
workRequestBuilder.addTag(Worker.WORK_TYPE_NOTIFICATION_TRIGGER);
|
|
679
|
+
workRequestBuilder.addTag(uniqueWorkName);
|
|
680
|
+
workDataBuilder.putString(Worker.KEY_WORK_REQUEST, Worker.WORK_REQUEST_ONE_TIME);
|
|
681
|
+
workRequestBuilder.setInputData(workDataBuilder.build());
|
|
682
|
+
workRequestBuilder.setInitialDelay(delay, TimeUnit.SECONDS);
|
|
683
|
+
workManager.enqueueUniqueWork(
|
|
684
|
+
uniqueWorkName, ExistingWorkPolicy.REPLACE, workRequestBuilder.build());
|
|
685
|
+
} else {
|
|
686
|
+
// WorkManager - repeat trigger
|
|
687
|
+
PeriodicWorkRequest.Builder workRequestBuilder;
|
|
688
|
+
|
|
689
|
+
workRequestBuilder =
|
|
690
|
+
new PeriodicWorkRequest.Builder(
|
|
691
|
+
Worker.class, trigger.getInterval(), trigger.getTimeUnit());
|
|
692
|
+
|
|
693
|
+
workRequestBuilder.addTag(Worker.WORK_TYPE_NOTIFICATION_TRIGGER);
|
|
694
|
+
workRequestBuilder.addTag(uniqueWorkName);
|
|
695
|
+
workRequestBuilder.setInitialDelay(delay, TimeUnit.SECONDS);
|
|
696
|
+
workDataBuilder.putString(Worker.KEY_WORK_REQUEST, Worker.WORK_REQUEST_PERIODIC);
|
|
697
|
+
workRequestBuilder.setInputData(workDataBuilder.build());
|
|
698
|
+
workManager.enqueueUniquePeriodicWork(
|
|
699
|
+
uniqueWorkName, ExistingPeriodicWorkPolicy.REPLACE, workRequestBuilder.build());
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
static ListenableFuture<List<Bundle>> getDisplayedNotifications() {
|
|
704
|
+
return LISTENING_CACHED_THREAD_POOL.submit(
|
|
705
|
+
() -> {
|
|
706
|
+
List<Bundle> notifications = new ArrayList<Bundle>();
|
|
707
|
+
|
|
708
|
+
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
|
709
|
+
return notifications;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
android.app.NotificationManager notificationManager =
|
|
713
|
+
(android.app.NotificationManager)
|
|
714
|
+
getApplicationContext().getSystemService(Context.NOTIFICATION_SERVICE);
|
|
715
|
+
|
|
716
|
+
StatusBarNotification delivered[] = notificationManager.getActiveNotifications();
|
|
717
|
+
|
|
718
|
+
for (StatusBarNotification sbNotification : delivered) {
|
|
719
|
+
Notification original = sbNotification.getNotification();
|
|
720
|
+
|
|
721
|
+
Bundle extras = original.extras;
|
|
722
|
+
Bundle displayNotificationBundle = new Bundle();
|
|
723
|
+
|
|
724
|
+
Bundle notificationBundle = extras.getBundle(EXTRA_NOTIFEE_NOTIFICATION);
|
|
725
|
+
Bundle triggerBundle = extras.getBundle(EXTRA_NOTIFEE_TRIGGER);
|
|
726
|
+
|
|
727
|
+
if (notificationBundle == null) {
|
|
728
|
+
notificationBundle = new Bundle();
|
|
729
|
+
notificationBundle.putString("id", "" + sbNotification.getId());
|
|
730
|
+
|
|
731
|
+
Object title = extras.get(Notification.EXTRA_TITLE);
|
|
732
|
+
|
|
733
|
+
if (title != null) {
|
|
734
|
+
notificationBundle.putString("title", title.toString());
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
Object text = extras.get(Notification.EXTRA_TEXT);
|
|
738
|
+
|
|
739
|
+
if (text != null) {
|
|
740
|
+
notificationBundle.putString("body", text.toString());
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
Object subtitle = extras.get(Notification.EXTRA_SUB_TEXT);
|
|
744
|
+
|
|
745
|
+
if (subtitle != null) {
|
|
746
|
+
notificationBundle.putString("subtitle", subtitle.toString());
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
Bundle androidBundle = new Bundle();
|
|
750
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
751
|
+
androidBundle.putString("channelId", original.getChannelId());
|
|
752
|
+
}
|
|
753
|
+
androidBundle.putString("tag", sbNotification.getTag());
|
|
754
|
+
androidBundle.putString("group", original.getGroup());
|
|
755
|
+
|
|
756
|
+
notificationBundle.putBundle("android", androidBundle);
|
|
757
|
+
|
|
758
|
+
displayNotificationBundle.putString("id", "" + sbNotification.getId());
|
|
759
|
+
} else {
|
|
760
|
+
displayNotificationBundle.putString("id", "" + notificationBundle.get("id"));
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
if (triggerBundle != null) {
|
|
764
|
+
displayNotificationBundle.putBundle("trigger", triggerBundle);
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
displayNotificationBundle.putBundle("notification", notificationBundle);
|
|
768
|
+
displayNotificationBundle.putString("date", "" + sbNotification.getPostTime());
|
|
769
|
+
|
|
770
|
+
notifications.add(displayNotificationBundle);
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
return notifications;
|
|
774
|
+
});
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
static void getTriggerNotifications(MethodCallResult<List<Bundle>> result) {
|
|
778
|
+
WorkDataRepository workDataRepository = new WorkDataRepository(getApplicationContext());
|
|
779
|
+
|
|
780
|
+
List<Bundle> triggerNotifications = new ArrayList<Bundle>();
|
|
781
|
+
|
|
782
|
+
Futures.addCallback(workDataRepository.getAll(),
|
|
783
|
+
new FutureCallback<List<WorkDataEntity>>() {
|
|
784
|
+
@Override
|
|
785
|
+
public void onSuccess(List<WorkDataEntity> workDataEntities) {
|
|
786
|
+
for (WorkDataEntity workDataEntity : workDataEntities) {
|
|
787
|
+
Bundle triggerNotificationBundle = new Bundle();
|
|
788
|
+
|
|
789
|
+
triggerNotificationBundle.putBundle(
|
|
790
|
+
"notification", ObjectUtils.bytesToBundle(workDataEntity.getNotification()));
|
|
791
|
+
|
|
792
|
+
triggerNotificationBundle.putBundle(
|
|
793
|
+
"trigger", ObjectUtils.bytesToBundle(workDataEntity.getTrigger()));
|
|
794
|
+
triggerNotifications.add(triggerNotificationBundle);
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
result.onComplete(null, triggerNotifications);
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
@Override
|
|
801
|
+
public void onFailure(Throwable t) {
|
|
802
|
+
result.onComplete(new Exception(t), triggerNotifications);
|
|
803
|
+
}
|
|
804
|
+
}, LISTENING_CACHED_THREAD_POOL);
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
static void getTriggerNotificationIds(MethodCallResult<List<String>> result) {
|
|
808
|
+
WorkDataRepository workDataRepository = new WorkDataRepository(getApplicationContext());
|
|
809
|
+
|
|
810
|
+
Futures.addCallback(workDataRepository
|
|
811
|
+
.getAll(),
|
|
812
|
+
new FutureCallback<List<WorkDataEntity>>() {
|
|
813
|
+
@Override
|
|
814
|
+
public void onSuccess(List<WorkDataEntity> workDataEntities) {
|
|
815
|
+
List<String> triggerNotificationIds = new ArrayList<String>();
|
|
816
|
+
for (WorkDataEntity workDataEntity : workDataEntities) {
|
|
817
|
+
triggerNotificationIds.add(workDataEntity.getId());
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
result.onComplete(null, triggerNotificationIds);
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
@Override
|
|
824
|
+
public void onFailure(Throwable t) {
|
|
825
|
+
result.onComplete(new Exception(t), null);
|
|
826
|
+
}
|
|
827
|
+
}, LISTENING_CACHED_THREAD_POOL);
|
|
828
|
+
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
/* Execute work from trigger notifications via WorkManager*/
|
|
832
|
+
static void doScheduledWork(
|
|
833
|
+
Data data, CallbackToFutureAdapter.Completer<ListenableWorker.Result> completer) {
|
|
834
|
+
|
|
835
|
+
String id = data.getString("id");
|
|
836
|
+
|
|
837
|
+
WorkDataRepository workDataRepository = new WorkDataRepository(getApplicationContext());
|
|
838
|
+
|
|
839
|
+
AsyncFunction<WorkDataEntity, ListenableFuture<Void>> workContinuation =
|
|
840
|
+
workDataEntity -> LISTENING_CACHED_THREAD_POOL.submit(() -> {
|
|
841
|
+
byte[] notificationBytes;
|
|
842
|
+
|
|
843
|
+
if (workDataEntity == null || workDataEntity.getNotification() == null) {
|
|
844
|
+
// check if notification bundle is stored with Work Manager
|
|
845
|
+
notificationBytes = data.getByteArray("notification");
|
|
846
|
+
if (notificationBytes != null) {
|
|
847
|
+
Logger.w(
|
|
848
|
+
TAG,
|
|
849
|
+
"The trigger notification was created using an older version, please consider"
|
|
850
|
+
+ " recreating the notification.");
|
|
851
|
+
} else {
|
|
852
|
+
Logger.w(
|
|
853
|
+
TAG, "Attempted to handle doScheduledWork but no notification data was found.");
|
|
854
|
+
completer.set(ListenableWorker.Result.success());
|
|
855
|
+
return Futures.immediateFuture(null);
|
|
856
|
+
}
|
|
857
|
+
} else {
|
|
858
|
+
notificationBytes = workDataEntity.getNotification();
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
NotificationModel notificationModel =
|
|
862
|
+
NotificationModel.fromBundle(ObjectUtils.bytesToBundle(notificationBytes));
|
|
863
|
+
|
|
864
|
+
byte[] triggerBytes = workDataEntity.getTrigger();
|
|
865
|
+
Bundle triggerBundle = null;
|
|
866
|
+
|
|
867
|
+
if (workDataEntity.getTrigger() != null) {
|
|
868
|
+
triggerBundle = ObjectUtils.bytesToBundle(triggerBytes);
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
return NotificationManager.displayNotification(notificationModel, triggerBundle);
|
|
872
|
+
});
|
|
873
|
+
|
|
874
|
+
new ExtendedListenableFuture<>(workDataRepository
|
|
875
|
+
.getWorkDataById(id))
|
|
876
|
+
.continueWith(workContinuation, LISTENING_CACHED_THREAD_POOL)
|
|
877
|
+
.addOnCompleteListener(
|
|
878
|
+
(e, result) -> {
|
|
879
|
+
if (e == null) {
|
|
880
|
+
new ExtendedListenableFuture<>(result).addOnCompleteListener(
|
|
881
|
+
(e2, _unused) -> {
|
|
882
|
+
completer.set(Result.success());
|
|
883
|
+
if (e2 != null) {
|
|
884
|
+
Logger.e(TAG, "Failed to display notification", e2);
|
|
885
|
+
} else {
|
|
886
|
+
String workerRequestType = data.getString(
|
|
887
|
+
Worker.KEY_WORK_REQUEST);
|
|
888
|
+
if (workerRequestType != null
|
|
889
|
+
&& workerRequestType.equals(
|
|
890
|
+
Worker.WORK_REQUEST_ONE_TIME)) {
|
|
891
|
+
// delete database entry if work is a one-time request
|
|
892
|
+
WorkDataRepository.getInstance(getApplicationContext())
|
|
893
|
+
.deleteById(id);
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
}, LISTENING_CACHED_THREAD_POOL);
|
|
897
|
+
} else {
|
|
898
|
+
completer.set(Result.success());
|
|
899
|
+
Logger.e(TAG, "Failed to display notification", e);
|
|
900
|
+
}
|
|
901
|
+
}, LISTENING_CACHED_THREAD_POOL);
|
|
902
|
+
}
|
|
903
|
+
}
|