1package eu.siacs.conversations.services;
2
3import android.app.Notification;
4import android.app.PendingIntent;
5import android.content.Intent;
6import android.content.SharedPreferences;
7import android.graphics.Bitmap;
8import android.net.Uri;
9import android.os.Build;
10import android.os.SystemClock;
11import android.support.v4.app.NotificationCompat;
12import android.support.v4.app.NotificationCompat.BigPictureStyle;
13import android.support.v4.app.NotificationCompat.Builder;
14import android.support.v4.app.NotificationManagerCompat;
15import android.support.v4.app.RemoteInput;
16import android.text.Html;
17import android.util.DisplayMetrics;
18import android.util.Log;
19
20import java.io.FileNotFoundException;
21import java.util.ArrayList;
22import java.util.Calendar;
23import java.util.LinkedHashMap;
24import java.util.List;
25import java.util.Map;
26import java.util.regex.Matcher;
27import java.util.regex.Pattern;
28
29import eu.siacs.conversations.Config;
30import eu.siacs.conversations.R;
31import eu.siacs.conversations.entities.Account;
32import eu.siacs.conversations.entities.Contact;
33import eu.siacs.conversations.entities.Conversation;
34import eu.siacs.conversations.entities.Message;
35import eu.siacs.conversations.ui.ConversationActivity;
36import eu.siacs.conversations.ui.ManageAccountActivity;
37import eu.siacs.conversations.ui.SettingsActivity;
38import eu.siacs.conversations.ui.TimePreference;
39import eu.siacs.conversations.utils.GeoHelper;
40import eu.siacs.conversations.utils.UIHelper;
41
42public class NotificationService {
43
44 private static final String CONVERSATIONS_GROUP = "eu.siacs.conversations";
45 private final XmppConnectionService mXmppConnectionService;
46
47 private final LinkedHashMap<String, ArrayList<Message>> notifications = new LinkedHashMap<>();
48
49 public static final int NOTIFICATION_ID = 0x2342;
50 public static final int FOREGROUND_NOTIFICATION_ID = 0x8899;
51 public static final int ERROR_NOTIFICATION_ID = 0x5678;
52
53 private Conversation mOpenConversation;
54 private boolean mIsInForeground;
55 private long mLastNotification;
56
57 public NotificationService(final XmppConnectionService service) {
58 this.mXmppConnectionService = service;
59 }
60
61 public boolean notify(final Message message) {
62 return (message.getStatus() == Message.STATUS_RECEIVED)
63 && notificationsEnabled()
64 && !message.getConversation().isMuted()
65 && (message.getConversation().alwaysNotify() || wasHighlightedOrPrivate(message)
66 );
67 }
68
69 public boolean notificationsEnabled() {
70 return mXmppConnectionService.getPreferences().getBoolean("show_notification", true);
71 }
72
73 public boolean isQuietHours() {
74 if (!mXmppConnectionService.getPreferences().getBoolean("enable_quiet_hours", false)) {
75 return false;
76 }
77 final long startTime = mXmppConnectionService.getPreferences().getLong("quiet_hours_start", TimePreference.DEFAULT_VALUE) % Config.MILLISECONDS_IN_DAY;
78 final long endTime = mXmppConnectionService.getPreferences().getLong("quiet_hours_end", TimePreference.DEFAULT_VALUE) % Config.MILLISECONDS_IN_DAY;
79 final long nowTime = Calendar.getInstance().getTimeInMillis() % Config.MILLISECONDS_IN_DAY;
80
81 if (endTime < startTime) {
82 return nowTime > startTime || nowTime < endTime;
83 } else {
84 return nowTime > startTime && nowTime < endTime;
85 }
86 }
87
88 public void pushFromBacklog(final Message message) {
89 if (notify(message)) {
90 synchronized (notifications) {
91 pushToStack(message);
92 }
93 }
94 }
95
96 public void pushFromDirectReply(final Message message) {
97 synchronized (notifications) {
98 pushToStack(message);
99 updateNotification(false);
100 }
101 }
102
103 public void finishBacklog(boolean notify) {
104 synchronized (notifications) {
105 mXmppConnectionService.updateUnreadCountBadge();
106 updateNotification(notify);
107 }
108 }
109
110 private void pushToStack(final Message message) {
111 final String conversationUuid = message.getConversationUuid();
112 if (notifications.containsKey(conversationUuid)) {
113 notifications.get(conversationUuid).add(message);
114 } else {
115 final ArrayList<Message> mList = new ArrayList<>();
116 mList.add(message);
117 notifications.put(conversationUuid, mList);
118 }
119 }
120
121 public void push(final Message message) {
122 mXmppConnectionService.updateUnreadCountBadge();
123 if (!notify(message)) {
124 Log.d(Config.LOGTAG,message.getConversation().getAccount().getJid().toBareJid()+": suppressing notification because turned off");
125 return;
126 }
127 final boolean isScreenOn = mXmppConnectionService.isInteractive();
128 if (this.mIsInForeground && isScreenOn && this.mOpenConversation == message.getConversation()) {
129 Log.d(Config.LOGTAG,message.getConversation().getAccount().getJid().toBareJid()+": suppressing notification because conversation is open");
130 return;
131 }
132 synchronized (notifications) {
133 pushToStack(message);
134 final Account account = message.getConversation().getAccount();
135 final boolean doNotify = (!(this.mIsInForeground && this.mOpenConversation == null) || !isScreenOn)
136 && !account.inGracePeriod()
137 && !this.inMiniGracePeriod(account);
138 updateNotification(doNotify);
139 }
140 }
141
142 public void clear() {
143 synchronized (notifications) {
144 for(ArrayList<Message> messages : notifications.values()) {
145 markAsReadIfHasDirectReply(messages);
146 }
147 notifications.clear();
148 updateNotification(false);
149 }
150 }
151
152 public void clear(final Conversation conversation) {
153 synchronized (notifications) {
154 markAsReadIfHasDirectReply(conversation);
155 notifications.remove(conversation.getUuid());
156 final NotificationManagerCompat notificationManager = NotificationManagerCompat.from(mXmppConnectionService);
157 notificationManager.cancel(conversation.getUuid(), NOTIFICATION_ID);
158 updateNotification(false);
159 }
160 }
161
162 private void markAsReadIfHasDirectReply(final Conversation conversation) {
163 markAsReadIfHasDirectReply(notifications.get(conversation.getUuid()));
164 }
165
166 private void markAsReadIfHasDirectReply(final ArrayList<Message> messages) {
167 if (messages != null && messages.size() > 0) {
168 Message last = messages.get(messages.size() - 1);
169 if (last.getStatus() != Message.STATUS_RECEIVED) {
170 mXmppConnectionService.markRead(last.getConversation(), false);
171 }
172 }
173 }
174
175 private void setNotificationColor(final Builder mBuilder) {
176 mBuilder.setColor(mXmppConnectionService.getResources().getColor(R.color.primary500));
177 }
178
179 public void updateNotification(final boolean notify) {
180 final NotificationManagerCompat notificationManager = NotificationManagerCompat.from(mXmppConnectionService);
181 final SharedPreferences preferences = mXmppConnectionService.getPreferences();
182
183 if (notifications.size() == 0) {
184 notificationManager.cancel(NOTIFICATION_ID);
185 } else {
186 if (notify) {
187 this.markLastNotification();
188 }
189 final Builder mBuilder;
190 if (notifications.size() == 1 && Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
191 mBuilder = buildSingleConversations(notifications.values().iterator().next());
192 modifyForSoundVibrationAndLight(mBuilder, notify, preferences);
193 notificationManager.notify(NOTIFICATION_ID, mBuilder.build());
194 } else {
195 mBuilder = buildMultipleConversation();
196 modifyForSoundVibrationAndLight(mBuilder, notify, preferences);
197 notificationManager.notify(NOTIFICATION_ID, mBuilder.build());
198 for(Map.Entry<String,ArrayList<Message>> entry : notifications.entrySet()) {
199 Builder singleBuilder = buildSingleConversations(entry.getValue());
200 singleBuilder.setGroup(CONVERSATIONS_GROUP);
201 modifyForSoundVibrationAndLight(singleBuilder,notify,preferences);
202 notificationManager.notify(entry.getKey(), NOTIFICATION_ID ,singleBuilder.build());
203 }
204 }
205 }
206 }
207
208
209 private void modifyForSoundVibrationAndLight(Builder mBuilder, boolean notify, SharedPreferences preferences) {
210 final String ringtone = preferences.getString("notification_ringtone", null);
211 final boolean vibrate = preferences.getBoolean("vibrate_on_notification", true);
212 final boolean led = preferences.getBoolean("led", true);
213 if (notify && !isQuietHours()) {
214 if (vibrate) {
215 final int dat = 70;
216 final long[] pattern = {0, 3 * dat, dat, dat};
217 mBuilder.setVibrate(pattern);
218 }
219 if (ringtone != null) {
220 mBuilder.setSound(Uri.parse(ringtone));
221 }
222 }
223 if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
224 mBuilder.setCategory(Notification.CATEGORY_MESSAGE);
225 }
226 setNotificationColor(mBuilder);
227 mBuilder.setDefaults(0);
228 if (led) {
229 mBuilder.setLights(0xff00FF00, 2000, 3000);
230 }
231 }
232
233 private Builder buildMultipleConversation() {
234 final Builder mBuilder = new NotificationCompat.Builder(
235 mXmppConnectionService);
236 final NotificationCompat.InboxStyle style = new NotificationCompat.InboxStyle();
237 style.setBigContentTitle(notifications.size()
238 + " "
239 + mXmppConnectionService
240 .getString(R.string.unread_conversations));
241 final StringBuilder names = new StringBuilder();
242 Conversation conversation = null;
243 for (final ArrayList<Message> messages : notifications.values()) {
244 if (messages.size() > 0) {
245 conversation = messages.get(0).getConversation();
246 final String name = conversation.getName();
247 if (Config.HIDE_MESSAGE_TEXT_IN_NOTIFICATION) {
248 int count = messages.size();
249 style.addLine(Html.fromHtml("<b>"+name+"</b>: "+mXmppConnectionService.getResources().getQuantityString(R.plurals.x_messages,count,count)));
250 } else {
251 style.addLine(Html.fromHtml("<b>" + name + "</b>: "
252 + UIHelper.getMessagePreview(mXmppConnectionService, messages.get(0)).first));
253 }
254 names.append(name);
255 names.append(", ");
256 }
257 }
258 if (names.length() >= 2) {
259 names.delete(names.length() - 2, names.length());
260 }
261 mBuilder.setContentTitle(notifications.size()
262 + " "
263 + mXmppConnectionService
264 .getString(R.string.unread_conversations));
265 mBuilder.setContentText(names.toString());
266 mBuilder.setStyle(style);
267 if (conversation != null) {
268 mBuilder.setContentIntent(createContentIntent(conversation));
269 }
270 mBuilder.setGroupSummary(true);
271 mBuilder.setGroup(CONVERSATIONS_GROUP);
272 mBuilder.setDeleteIntent(createDeleteIntent(null));
273 mBuilder.setSmallIcon(R.drawable.ic_notification);
274 return mBuilder;
275 }
276
277 private Builder buildSingleConversations(final ArrayList<Message> messages) {
278 final Builder mBuilder = new NotificationCompat.Builder(mXmppConnectionService);
279 if (messages.size() >= 1) {
280 final Conversation conversation = messages.get(0).getConversation();
281 mBuilder.setLargeIcon(mXmppConnectionService.getAvatarService()
282 .get(conversation, getPixel(64)));
283 mBuilder.setContentTitle(conversation.getName());
284 if (Config.HIDE_MESSAGE_TEXT_IN_NOTIFICATION) {
285 int count = messages.size();
286 mBuilder.setContentText(mXmppConnectionService.getResources().getQuantityString(R.plurals.x_messages,count,count));
287 } else {
288 Message message;
289 if ((message = getImage(messages)) != null) {
290 modifyForImage(mBuilder, message, messages);
291 } else {
292 modifyForTextOnly(mBuilder, messages);
293 }
294 RemoteInput remoteInput = new RemoteInput.Builder("text_reply").setLabel(UIHelper.getMessageHint(mXmppConnectionService, conversation)).build();
295 NotificationCompat.Action replyAction = new NotificationCompat.Action.Builder(R.drawable.ic_send_text_offline, "Reply", createReplyIntent(conversation, false)).addRemoteInput(remoteInput).build();
296 NotificationCompat.Action wearReplyAction = new NotificationCompat.Action.Builder(R.drawable.ic_send_text_offline, "Reply", createReplyIntent(conversation, true)).addRemoteInput(remoteInput).build();
297 mBuilder.extend(new NotificationCompat.WearableExtender().addAction(wearReplyAction));
298 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
299 mBuilder.addAction(replyAction);
300 }
301 if ((message = getFirstDownloadableMessage(messages)) != null) {
302 mBuilder.addAction(
303 Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ?
304 R.drawable.ic_file_download_white_24dp : R.drawable.ic_action_download,
305 mXmppConnectionService.getResources().getString(R.string.download_x_file,
306 UIHelper.getFileDescriptionString(mXmppConnectionService, message)),
307 createDownloadIntent(message)
308 );
309 }
310 if ((message = getFirstLocationMessage(messages)) != null) {
311 mBuilder.addAction(R.drawable.ic_room_white_24dp,
312 mXmppConnectionService.getString(R.string.show_location),
313 createShowLocationIntent(message));
314 }
315 }
316 if (conversation.getMode() == Conversation.MODE_SINGLE) {
317 Contact contact = conversation.getContact();
318 Uri systemAccount = contact.getSystemAccount();
319 if (systemAccount != null) {
320 mBuilder.addPerson(systemAccount.toString());
321 }
322 }
323 mBuilder.setWhen(conversation.getLatestMessage().getTimeSent());
324 mBuilder.setSmallIcon(R.drawable.ic_notification);
325 mBuilder.setDeleteIntent(createDeleteIntent(conversation));
326 mBuilder.setContentIntent(createContentIntent(conversation));
327 }
328 return mBuilder;
329 }
330
331 private void modifyForImage(final Builder builder, final Message message,
332 final ArrayList<Message> messages) {
333 try {
334 final Bitmap bitmap = mXmppConnectionService.getFileBackend()
335 .getThumbnail(message, getPixel(288), false);
336 final ArrayList<Message> tmp = new ArrayList<>();
337 for (final Message msg : messages) {
338 if (msg.getType() == Message.TYPE_TEXT
339 && msg.getTransferable() == null) {
340 tmp.add(msg);
341 }
342 }
343 final BigPictureStyle bigPictureStyle = new NotificationCompat.BigPictureStyle();
344 bigPictureStyle.bigPicture(bitmap);
345 if (tmp.size() > 0) {
346 CharSequence text = getMergedBodies(tmp);
347 bigPictureStyle.setSummaryText(text);
348 builder.setContentText(text);
349 } else {
350 builder.setContentText(mXmppConnectionService.getString(
351 R.string.received_x_file,
352 UIHelper.getFileDescriptionString(mXmppConnectionService, message)));
353 }
354 builder.setStyle(bigPictureStyle);
355 } catch (final FileNotFoundException e) {
356 modifyForTextOnly(builder, messages);
357 }
358 }
359
360 private void modifyForTextOnly(final Builder builder, final ArrayList<Message> messages) {
361 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
362 NotificationCompat.MessagingStyle messagingStyle = new NotificationCompat.MessagingStyle(mXmppConnectionService.getString(R.string.me));
363 Conversation conversation = messages.get(0).getConversation();
364 if (conversation.getMode() == Conversation.MODE_MULTI) {
365 messagingStyle.setConversationTitle(conversation.getName());
366 }
367 for (Message message : messages) {
368 String sender = message.getStatus() == Message.STATUS_RECEIVED ? UIHelper.getMessageDisplayName(message) : null;
369 messagingStyle.addMessage(UIHelper.getMessagePreview(mXmppConnectionService,message).first, message.getTimeSent(), sender);
370 }
371 builder.setStyle(messagingStyle);
372 } else {
373 builder.setStyle(new NotificationCompat.BigTextStyle().bigText(getMergedBodies(messages)));
374 builder.setContentText(UIHelper.getMessagePreview(mXmppConnectionService, messages.get((messages.size()-1))).first);
375 }
376 }
377
378 private Message getImage(final Iterable<Message> messages) {
379 Message image = null;
380 for (final Message message : messages) {
381 if (message.getStatus() != Message.STATUS_RECEIVED) {
382 return null;
383 }
384 if (message.getType() != Message.TYPE_TEXT
385 && message.getTransferable() == null
386 && message.getEncryption() != Message.ENCRYPTION_PGP
387 && message.getFileParams().height > 0) {
388 image = message;
389 }
390 }
391 return image;
392 }
393
394 private Message getFirstDownloadableMessage(final Iterable<Message> messages) {
395 for (final Message message : messages) {
396 if (message.getTransferable() != null
397 && (message.getType() == Message.TYPE_FILE
398 || message.getType() == Message.TYPE_IMAGE
399 || message.treatAsDownloadable() != Message.Decision.NEVER)) {
400 return message;
401 }
402 }
403 return null;
404 }
405
406 private Message getFirstLocationMessage(final Iterable<Message> messages) {
407 for (final Message message : messages) {
408 if (GeoHelper.isGeoUri(message.getBody())) {
409 return message;
410 }
411 }
412 return null;
413 }
414
415 private CharSequence getMergedBodies(final ArrayList<Message> messages) {
416 final StringBuilder text = new StringBuilder();
417 for (int i = 0; i < messages.size(); ++i) {
418 text.append(UIHelper.getMessagePreview(mXmppConnectionService, messages.get(i)).first);
419 if (i != messages.size() - 1) {
420 text.append("\n");
421 }
422 }
423 return text.toString();
424 }
425
426 private PendingIntent createShowLocationIntent(final Message message) {
427 Iterable<Intent> intents = GeoHelper.createGeoIntentsFromMessage(message);
428 for (Intent intent : intents) {
429 if (intent.resolveActivity(mXmppConnectionService.getPackageManager()) != null) {
430 return PendingIntent.getActivity(mXmppConnectionService, 18, intent, PendingIntent.FLAG_UPDATE_CURRENT);
431 }
432 }
433 return createOpenConversationsIntent();
434 }
435
436 private PendingIntent createContentIntent(final String conversationUuid, final String downloadMessageUuid) {
437 final Intent viewConversationIntent = new Intent(mXmppConnectionService,ConversationActivity.class);
438 viewConversationIntent.setAction(ConversationActivity.ACTION_VIEW_CONVERSATION);
439 viewConversationIntent.putExtra(ConversationActivity.CONVERSATION, conversationUuid);
440 if (downloadMessageUuid != null) {
441 viewConversationIntent.putExtra(ConversationActivity.EXTRA_DOWNLOAD_UUID, downloadMessageUuid);
442 return PendingIntent.getActivity(mXmppConnectionService,
443 conversationUuid.hashCode() % 389782,
444 viewConversationIntent,
445 PendingIntent.FLAG_UPDATE_CURRENT);
446 } else {
447 return PendingIntent.getActivity(mXmppConnectionService,
448 conversationUuid.hashCode() % 936236,
449 viewConversationIntent,
450 PendingIntent.FLAG_UPDATE_CURRENT);
451 }
452 }
453
454 private PendingIntent createDownloadIntent(final Message message) {
455 return createContentIntent(message.getConversationUuid(), message.getUuid());
456 }
457
458 private PendingIntent createContentIntent(final Conversation conversation) {
459 return createContentIntent(conversation.getUuid(), null);
460 }
461
462 private PendingIntent createDeleteIntent(Conversation conversation) {
463 final Intent intent = new Intent(mXmppConnectionService, XmppConnectionService.class);
464 intent.setAction(XmppConnectionService.ACTION_CLEAR_NOTIFICATION);
465 if (conversation != null) {
466 intent.putExtra("uuid", conversation.getUuid());
467 return PendingIntent.getService(mXmppConnectionService, conversation.getUuid().hashCode() % 247527, intent, 0);
468 }
469 return PendingIntent.getService(mXmppConnectionService, 0, intent, 0);
470 }
471
472 private PendingIntent createReplyIntent(Conversation conversation, boolean dismissAfterReply) {
473 final Intent intent = new Intent(mXmppConnectionService, XmppConnectionService.class);
474 intent.setAction(XmppConnectionService.ACTION_REPLY_TO_CONVERSATION);
475 intent.putExtra("uuid",conversation.getUuid());
476 intent.putExtra("dismiss_notification",dismissAfterReply);
477 int id = conversation.getUuid().hashCode() % (dismissAfterReply ? 402359 : 426583);
478 return PendingIntent.getService(mXmppConnectionService, id, intent, 0);
479 }
480
481 private PendingIntent createDisableForeground() {
482 final Intent intent = new Intent(mXmppConnectionService,
483 XmppConnectionService.class);
484 intent.setAction(XmppConnectionService.ACTION_DISABLE_FOREGROUND);
485 return PendingIntent.getService(mXmppConnectionService, 34, intent, 0);
486 }
487
488 private PendingIntent createTryAgainIntent() {
489 final Intent intent = new Intent(mXmppConnectionService, XmppConnectionService.class);
490 intent.setAction(XmppConnectionService.ACTION_TRY_AGAIN);
491 return PendingIntent.getService(mXmppConnectionService, 45, intent, 0);
492 }
493
494 private PendingIntent createDismissErrorIntent() {
495 final Intent intent = new Intent(mXmppConnectionService, XmppConnectionService.class);
496 intent.setAction(XmppConnectionService.ACTION_DISMISS_ERROR_NOTIFICATIONS);
497 return PendingIntent.getService(mXmppConnectionService, 69, intent, 0);
498 }
499
500 private boolean wasHighlightedOrPrivate(final Message message) {
501 final String nick = message.getConversation().getMucOptions().getActualNick();
502 final Pattern highlight = generateNickHighlightPattern(nick);
503 if (message.getBody() == null || nick == null) {
504 return false;
505 }
506 final Matcher m = highlight.matcher(message.getBody());
507 return (m.find() || message.getType() == Message.TYPE_PRIVATE);
508 }
509
510 private static Pattern generateNickHighlightPattern(final String nick) {
511 // We expect a word boundary, i.e. space or start of string, followed by
512 // the
513 // nick (matched in case-insensitive manner), followed by optional
514 // punctuation (for example "bob: i disagree" or "how are you alice?"),
515 // followed by another word boundary.
516 return Pattern.compile("\\b" + Pattern.quote(nick) + "\\p{Punct}?\\b",
517 Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
518 }
519
520 public void setOpenConversation(final Conversation conversation) {
521 this.mOpenConversation = conversation;
522 }
523
524 public void setIsInForeground(final boolean foreground) {
525 this.mIsInForeground = foreground;
526 }
527
528 private int getPixel(final int dp) {
529 final DisplayMetrics metrics = mXmppConnectionService.getResources()
530 .getDisplayMetrics();
531 return ((int) (dp * metrics.density));
532 }
533
534 private void markLastNotification() {
535 this.mLastNotification = SystemClock.elapsedRealtime();
536 }
537
538 private boolean inMiniGracePeriod(final Account account) {
539 final int miniGrace = account.getStatus() == Account.State.ONLINE ? Config.MINI_GRACE_PERIOD
540 : Config.MINI_GRACE_PERIOD * 2;
541 return SystemClock.elapsedRealtime() < (this.mLastNotification + miniGrace);
542 }
543
544 public Notification createForegroundNotification() {
545 final NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(mXmppConnectionService);
546
547 mBuilder.setContentTitle(mXmppConnectionService.getString(R.string.conversations_foreground_service));
548 if (Config.SHOW_CONNECTED_ACCOUNTS) {
549 List<Account> accounts = mXmppConnectionService.getAccounts();
550 int enabled = 0;
551 int connected = 0;
552 for (Account account : accounts) {
553 if (account.isOnlineAndConnected()) {
554 connected++;
555 enabled++;
556 } else if (!account.isOptionSet(Account.OPTION_DISABLED)) {
557 enabled++;
558 }
559 }
560 mBuilder.setContentText(mXmppConnectionService.getString(R.string.connected_accounts, connected, enabled));
561 } else {
562 mBuilder.setContentText(mXmppConnectionService.getString(R.string.touch_to_open_conversations));
563 }
564 mBuilder.setContentIntent(createOpenConversationsIntent());
565 mBuilder.setWhen(0);
566 mBuilder.setPriority(Config.SHOW_CONNECTED_ACCOUNTS ? NotificationCompat.PRIORITY_DEFAULT : NotificationCompat.PRIORITY_MIN);
567 mBuilder.setSmallIcon(R.drawable.ic_link_white_24dp);
568 if (Config.SHOW_DISABLE_FOREGROUND) {
569 final int cancelIcon;
570 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
571 mBuilder.setCategory(Notification.CATEGORY_SERVICE);
572 cancelIcon = R.drawable.ic_cancel_white_24dp;
573 } else {
574 cancelIcon = R.drawable.ic_action_cancel;
575 }
576 mBuilder.addAction(cancelIcon,
577 mXmppConnectionService.getString(R.string.disable_foreground_service),
578 createDisableForeground());
579 }
580 return mBuilder.build();
581 }
582
583 private PendingIntent createOpenConversationsIntent() {
584 return PendingIntent.getActivity(mXmppConnectionService, 0, new Intent(mXmppConnectionService, ConversationActivity.class), 0);
585 }
586
587 public void updateErrorNotification() {
588 final NotificationManagerCompat notificationManager = NotificationManagerCompat.from(mXmppConnectionService);
589 final List<Account> errors = new ArrayList<>();
590 for (final Account account : mXmppConnectionService.getAccounts()) {
591 if (account.hasErrorStatus() && account.showErrorNotification()) {
592 errors.add(account);
593 }
594 }
595 if (mXmppConnectionService.getPreferences().getBoolean(SettingsActivity.KEEP_FOREGROUND_SERVICE, false)) {
596 notificationManager.notify(FOREGROUND_NOTIFICATION_ID, createForegroundNotification());
597 }
598 final NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(mXmppConnectionService);
599 if (errors.size() == 0) {
600 notificationManager.cancel(ERROR_NOTIFICATION_ID);
601 return;
602 } else if (errors.size() == 1) {
603 mBuilder.setContentTitle(mXmppConnectionService.getString(R.string.problem_connecting_to_account));
604 mBuilder.setContentText(errors.get(0).getJid().toBareJid().toString());
605 } else {
606 mBuilder.setContentTitle(mXmppConnectionService.getString(R.string.problem_connecting_to_accounts));
607 mBuilder.setContentText(mXmppConnectionService.getString(R.string.touch_to_fix));
608 }
609 mBuilder.addAction(R.drawable.ic_autorenew_white_24dp,
610 mXmppConnectionService.getString(R.string.try_again),
611 createTryAgainIntent());
612 mBuilder.setDeleteIntent(createDismissErrorIntent());
613 mBuilder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
614 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
615 mBuilder.setSmallIcon(R.drawable.ic_warning_white_24dp);
616 } else {
617 mBuilder.setSmallIcon(R.drawable.ic_stat_alert_warning);
618 }
619 mBuilder.setContentIntent(PendingIntent.getActivity(mXmppConnectionService,
620 145,
621 new Intent(mXmppConnectionService,ManageAccountActivity.class),
622 PendingIntent.FLAG_UPDATE_CURRENT));
623 notificationManager.notify(ERROR_NOTIFICATION_ID, mBuilder.build());
624 }
625}