/** * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. */ package com.ubergeek42.WeechatAndroid.service; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Build; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.v4.app.NotificationCompat; import android.text.TextUtils; import com.ubergeek42.WeechatAndroid.BuildConfig; import com.ubergeek42.WeechatAndroid.R; import com.ubergeek42.WeechatAndroid.WeechatActivity; import com.ubergeek42.WeechatAndroid.relay.BufferList; import static com.ubergeek42.WeechatAndroid.service.RelayService.STATE.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.HashSet; import java.util.List; import java.util.Set; public class Notificator { private static Logger logger = LoggerFactory.getLogger("Notificator"); final private static boolean DEBUG_NOTIFICATIONS = false; final private static int NOTIFICATION_MAIN_ID = 42; final private static int NOTIFICATION_HOT_ID = 43; private static Context context; private static NotificationManager manager; public static void init(Context c) { context = c.getApplicationContext(); manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); } //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// public static void showMain(@NonNull RelayService relay, @NonNull String content, @Nullable PendingIntent intent) { showMain(relay, content, content, intent); } /** show the persistent notification of the service * * @param tickerText text that flashes a bit; doesn't appear on L+ * @param content the smaller text that appears under title * @param intent intent that's executed on notification click, default used if null */ public static void showMain(@NonNull RelayService relay, @Nullable String tickerText, @NonNull String content, @Nullable PendingIntent intent) { if (DEBUG_NOTIFICATIONS) logger.debug("showMain({}, {}, {})", tickerText, content, intent); PendingIntent contentIntent = (intent != null) ? intent : PendingIntent.getActivity(context, 0, new Intent(context, WeechatActivity.class), PendingIntent.FLAG_CANCEL_CURRENT); int icon = relay.state.contains(AUTHENTICATED) ? R.drawable.ic_connected : R.drawable.ic_disconnected; // use application context because of a bug in android: passed context will get leaked NotificationCompat.Builder builder = new NotificationCompat.Builder(context); builder.setContentIntent(contentIntent) .setSmallIcon(icon) .setContentTitle("WeechatAndroid " + BuildConfig.VERSION_NAME) .setContentText(content) .setWhen(System.currentTimeMillis()); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) builder.setPriority(Notification.PRIORITY_MIN); if (P.notificationTicker) builder.setTicker(tickerText); String disconnectText = context.getString(relay.state.contains(AUTHENTICATED) ? R.string.disconnect : R.string.stop_connecting); builder.addAction( android.R.drawable.ic_menu_close_clear_cancel, disconnectText, PendingIntent.getService( context, 0, new Intent(RelayService.ACTION_STOP, null, context, RelayService.class), 0 ) ); Notification notification = builder.build(); notification.flags |= Notification.FLAG_ONGOING_EVENT; relay.startForeground(NOTIFICATION_MAIN_ID, notification); } //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////// private static final int BUFFER = 0, LINE = 1; /** display notification with a hot message ** clicking on it will open the buffer & scroll up to the hot line, if needed ** mind that SOMETIMES hotCount will be larger than hotList, because ** it's filled from hotlist data and hotList only contains lines that ** arrived in real time. so we add (message not available) if there are NO lines to display ** and add "..." if there are some lines to display, but not all */ public static void showHot(boolean newHighlight) { if (DEBUG_NOTIFICATIONS) logger.debug("showHot({})", newHighlight); if (!P.notificationEnable) return; final int hotCount = BufferList.getHotCount(); final List<String[]> hotList = BufferList.hotList; if (hotCount == 0) { manager.cancel(NOTIFICATION_HOT_ID); return; } // find our target buffer. if ALL items point to the same buffer, use it, // otherwise, go to buffer list (→ "") Set<String> set = new HashSet<>(); for (String[] h: hotList) set.add(h[BUFFER]); String target_buffer = (hotCount == hotList.size() && set.size() == 1) ? hotList.get(0)[BUFFER] : ""; // prepare intent Intent intent = new Intent(context, WeechatActivity.class).putExtra("full_name", target_buffer); PendingIntent contentIntent = PendingIntent.getActivity(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT); // prepare notification // make the ticker the LAST message String message = hotList.size() == 0 ? context.getString(R.string.hot_message_not_available) : hotList.get(hotList.size() - 1)[LINE]; NotificationCompat.Builder builder = new NotificationCompat.Builder(context) .setContentIntent(contentIntent) .setSmallIcon(R.drawable.ic_hot) .setContentTitle(context.getResources().getQuantityString(R.plurals.hot_messages, hotCount, hotCount)) .setContentText(message); // display several lines only if we have at least one visible line and // 2 or more lines total. that is, either display full list of lines or // one ore more visible lines and "..." if (hotList.size() > 0 && hotCount > 1) { NotificationCompat.InboxStyle inbox = new NotificationCompat.InboxStyle() .setSummaryText(P.printableHost); for (String[] bufferToLine : hotList) inbox.addLine(bufferToLine[LINE]); if (hotList.size() < hotCount) inbox.addLine("…"); builder.setContentInfo(String.valueOf(hotCount)); builder.setStyle(inbox); } if (newHighlight) { builder.setTicker(message); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) builder.setPriority(Notification.PRIORITY_HIGH); if (!TextUtils.isEmpty(P.notificationSound)) builder.setSound(Uri.parse(P.notificationSound)); int flags = 0; if (P.notificationLight) flags |= Notification.DEFAULT_LIGHTS; if (P.notificationVibrate) flags |= Notification.DEFAULT_VIBRATE; builder.setDefaults(flags); } manager.notify(NOTIFICATION_HOT_ID, builder.build()); } }