-
Notifications
You must be signed in to change notification settings - Fork 4.8k
/
ExpoNotificationBuilder.java
219 lines (184 loc) · 7.85 KB
/
ExpoNotificationBuilder.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
package expo.modules.notifications.notifications.presentation.builders;
import android.app.Notification;
import android.app.NotificationChannel;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.unimodules.core.ModuleRegistry;
import org.unimodules.interfaces.imageloader.ImageLoader;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import androidx.core.app.NotificationCompat;
import expo.modules.notifications.notifications.interfaces.NotificationBuilder;
/**
* {@link NotificationBuilder} interpreting a JSON request object.
*/
public class ExpoNotificationBuilder implements NotificationBuilder {
private static final String CONTENT_TITLE_KEY = "title";
private static final String CONTENT_TEXT_KEY = "message";
private static final String CONTENT_SUBTITLE_KEY = "subtitle";
private static final String SOUND_KEY = "sound";
private static final String BADGE_KEY = "badge";
private static final String BODY_KEY = "body";
private static final String PRIORITY_KEY = "priority";
private static final String VIBRATE_KEY = "vibrate";
private static final String THUMBNAIL_URI_KEY = "thumbnailUri";
private static final String EXTRAS_BADGE_KEY = "badge";
private static final String EXTRAS_BODY_KEY = "body";
private static final long[] NO_VIBRATE_PATTERN = new long[]{0, 0};
private final Context mContext;
private JSONObject mNotificationRequest;
private ImageLoader mImageLoader;
public ExpoNotificationBuilder(Context context, ModuleRegistry moduleRegistry) {
mContext = context;
mImageLoader = moduleRegistry.getModule(ImageLoader.class);
}
public ExpoNotificationBuilder setNotificationRequest(JSONObject notificationRequest) {
mNotificationRequest = notificationRequest;
return this;
}
protected NotificationCompat.Builder createBuilder() {
NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext, getChannelId());
builder.setSmallIcon(mContext.getApplicationInfo().icon);
// We're setting the content only if there is anything to set
// otherwise the content title and text are displayed
// as if they were empty strings.
if (!mNotificationRequest.isNull(CONTENT_TITLE_KEY)) {
builder.setContentTitle(mNotificationRequest.optString(CONTENT_TITLE_KEY));
}
if (!mNotificationRequest.isNull(CONTENT_TEXT_KEY)) {
builder.setContentText(mNotificationRequest.optString(CONTENT_TEXT_KEY));
}
if (!mNotificationRequest.isNull(CONTENT_SUBTITLE_KEY)) {
builder.setSubText(mNotificationRequest.optString(CONTENT_SUBTITLE_KEY));
}
if (shouldShowAlert()) {
// Display as a heads-up notification
builder.setPriority(NotificationCompat.PRIORITY_HIGH);
} else {
// Do not display as a heads-up notification, but show in the notification tray
builder.setPriority(NotificationCompat.PRIORITY_DEFAULT);
}
Number priorityOverride = getPriorityOverride();
if (priorityOverride != null) {
builder.setPriority(priorityOverride.intValue());
}
if (shouldPlaySound()) {
// Attach default notification sound to the NotificationCompat.Builder
builder.setSound(Settings.System.DEFAULT_NOTIFICATION_URI);
} else {
// Remove any sound attached to the NotificationCompat.Builder
builder.setSound(null);
}
if (shouldPlaySound() && shouldUseDefaultVibration()) {
builder.setDefaults(NotificationCompat.DEFAULT_ALL); // sets default vibration too
} else if (shouldUseDefaultVibration()) {
builder.setDefaults(NotificationCompat.DEFAULT_VIBRATE);
} else if (shouldPlaySound()) {
builder.setDefaults(NotificationCompat.DEFAULT_SOUND);
} else {
// Remove any sound or vibration attached by notification options.
builder.setDefaults(0);
// Remove any vibration pattern attached to the builder by overriding
// it with a no-vibrate pattern. It also doubles as a cue for the OS
// that given high priority it should be displayed as a heads-up notification.
builder.setVibrate(NO_VIBRATE_PATTERN);
}
long[] vibrationPatternOverride = getVibrationPatternOverride();
if (vibrationPatternOverride != null) {
builder.setVibrate(vibrationPatternOverride);
}
if (shouldSetBadge()) {
// TODO: Set badge as an effect of presenting notification,
// not as an effect of building a notification.
Bundle extras = builder.getExtras();
extras.putInt(EXTRAS_BADGE_KEY, getBadgeCount());
builder.setExtras(extras);
}
// Add body - JSON data - to extras
Bundle extras = builder.getExtras();
extras.putString(EXTRAS_BODY_KEY, mNotificationRequest.optString(BODY_KEY));
builder.setExtras(extras);
if (!mNotificationRequest.isNull(THUMBNAIL_URI_KEY)) {
try {
String thumbnailUri = mNotificationRequest.optString("thumbnailUri");
builder.setLargeIcon(mImageLoader.loadImageForDisplayFromURL(thumbnailUri).get(5, TimeUnit.SECONDS));
} catch (ExecutionException | InterruptedException e) {
Log.w("expo-notifications", "An exception was thrown in process of fetching a large icon.");
} catch (TimeoutException e) {
Log.w("expo-notifications", "Fetching large icon timed out. Consider using a smaller bitmap.");
}
}
return builder;
}
@Override
public Notification build() {
return createBuilder().build();
}
/**
* @return A {@link NotificationChannel}'s identifier to use for the notification.
*/
protected String getChannelId() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
// Returning null on incompatible platforms won't be an error.
return null;
}
// We need a channel ID, but we don't know any. Let's use system-provided one as a fallback.
Log.w("ExpoNotificationBuilder", "Using `NotificationChannel.DEFAULT_CHANNEL_ID` as channel ID for push notification. " +
"Please provide a NotificationChannelsManager to provide builder with a fallback channel ID.");
return NotificationChannel.DEFAULT_CHANNEL_ID;
}
private int getBadgeCount() {
return mNotificationRequest.optInt(BADGE_KEY);
}
private boolean shouldShowAlert() {
return !mNotificationRequest.isNull(CONTENT_TITLE_KEY) || !mNotificationRequest.isNull(CONTENT_TEXT_KEY);
}
private boolean shouldPlaySound() {
return mNotificationRequest.optBoolean(SOUND_KEY);
}
private boolean shouldUseDefaultVibration() {
return mNotificationRequest.optBoolean(SOUND_KEY) || mNotificationRequest.optBoolean(VIBRATE_KEY);
}
private boolean shouldSetBadge() {
return !mNotificationRequest.isNull(BADGE_KEY);
}
private Number getPriorityOverride() {
if (mNotificationRequest.isNull(PRIORITY_KEY)) {
return null;
}
switch (mNotificationRequest.optString(PRIORITY_KEY)) {
case "max":
return NotificationCompat.PRIORITY_MAX;
case "high":
return NotificationCompat.PRIORITY_HIGH;
case "low":
return NotificationCompat.PRIORITY_LOW;
case "min":
return NotificationCompat.PRIORITY_MIN;
default:
return null;
}
}
private long[] getVibrationPatternOverride() {
try {
JSONArray vibrateJsonArray = mNotificationRequest.optJSONArray(VIBRATE_KEY);
if (vibrateJsonArray != null) {
long[] pattern = new long[vibrateJsonArray.length()];
for (int i = 0; i < vibrateJsonArray.length(); i++) {
pattern[i] = vibrateJsonArray.getLong(i);
}
return pattern;
}
} catch (JSONException e) {
Log.w("expo-notifications", "Failed to set custom vibration pattern from the notification: " + e.getMessage());
}
return null;
}
}