From 539547b04d0ca852e028376f36643039755fd0b3 Mon Sep 17 00:00:00 2001 From: "K. Shankari" Date: Mon, 11 Mar 2019 22:46:36 -0700 Subject: [PATCH 1/2] Specify a channelID for use with the notification builder We re-use the same channel ID as the push plugin https://github.com/e-mission/e-mission-docs/issues/325#issuecomment-471849533 --- plugin.xml | 2 +- src/android/NotificationHelper.java | 37 +++++++++++++++++++++-------- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/plugin.xml b/plugin.xml index ec8a519..5283ff3 100644 --- a/plugin.xml +++ b/plugin.xml @@ -1,7 +1,7 @@ + version="1.3.0"> UnifiedLogger Log messages from both native code and javacript. Since this is diff --git a/src/android/NotificationHelper.java b/src/android/NotificationHelper.java index 021afbc..f1e9279 100644 --- a/src/android/NotificationHelper.java +++ b/src/android/NotificationHelper.java @@ -1,12 +1,14 @@ package edu.berkeley.eecs.emission.cordova.unifiedlogger; import android.app.Notification; +import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.os.Build; import android.os.Bundle; import android.support.v4.app.NotificationCompat; @@ -14,13 +16,18 @@ import edu.berkeley.eecs.emission.MainActivity; import edu.berkeley.eecs.emission.R; +import java.util.List; + public class NotificationHelper { private static String TAG = "NotificationHelper"; public static final String RESOLUTION_PENDING_INTENT_KEY = "rpIntentKey"; public static void createNotification(Context context, int id, String message) { - Notification.Builder builder = getNotificationBuilderForApp(context, message); + NotificationManager nMgr = + (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); + + Notification.Builder builder = getNotificationBuilderForApp(context, nMgr, message); /* * This is a bit of magic voodoo. The tutorial on launching the activity actually uses a stackbuilder * to create a fake stack for the new activity. However, it looks like the stackbuilder @@ -37,9 +44,6 @@ public static void createNotification(Context context, int id, String message) { activityIntent, PendingIntent.FLAG_UPDATE_CURRENT); builder.setContentIntent(activityPendingIntent); - NotificationManager nMgr = - (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); - Log.d(context, TAG, "Generating notify with id " + id + " and message " + message); nMgr.notify(id, builder.build()); } @@ -48,7 +52,10 @@ public static void createNotification(Context context, int id, String message) { * Used to show a pending intent - e.g. to turn on location services */ public static void createNotification(Context context, int id, String message, PendingIntent intent) { - Notification.Builder builder = getNotificationBuilderForApp(context, message); + NotificationManager nMgr = + (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); + + Notification.Builder builder = getNotificationBuilderForApp(context, nMgr, message); /* * This is a bit of magic voodoo. The tutorial on launching the activity actually uses a stackbuilder @@ -68,9 +75,6 @@ public static void createNotification(Context context, int id, String message, P builder.setContentIntent(activityPendingIntent); // builder.setAutoCancel(true); - NotificationManager nMgr = - (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); - Log.d(context, TAG, "Generating notify with id " + id + ", message " + message + " and pending intent " + intent); nMgr.notify(id, builder.build()); @@ -84,8 +88,21 @@ public static void cancelNotification(Context context, int id) { nMgr.cancel(id); } - public static Notification.Builder getNotificationBuilderForApp(Context context, String message) { - Notification.Builder builder = new Notification.Builder(context); + public static Notification.Builder getNotificationBuilderForApp(Context context, + NotificationManager nMgr, + String message) { + Notification.Builder builder = null; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + List channels = nMgr.getNotificationChannels(); + String channelID; + if (channels.size() < 1) { + throw new AssertionError("Did not find any channels, no notifications will be generated"); + } + channelID = channels.get(0).getId(); + builder = new Notification.Builder(context, channelID); + } else { + builder = new Notification.Builder(context); + } Bitmap appIcon = BitmapFactory.decodeResource(context.getResources(), R.mipmap.icon); builder.setLargeIcon(appIcon); builder.setSmallIcon(R.drawable.ic_visibility_black); From 6d364dcdb491e94488204db66270d4a6e089bc6a Mon Sep 17 00:00:00 2001 From: "K. Shankari" Date: Tue, 12 Mar 2019 11:33:34 -0700 Subject: [PATCH 2/2] Create a default channel and display the notification in it As part of the move to API 26, create a default channel and display the notification in it https://github.com/e-mission/e-mission-docs/issues/325#issuecomment-471849533 Bonus fix: - support pending intents that come from a resolution + pending intents that the activity knows how to handle directly --- src/android/NotificationHelper.java | 62 +++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 17 deletions(-) diff --git a/src/android/NotificationHelper.java b/src/android/NotificationHelper.java index f1e9279..ca024c0 100644 --- a/src/android/NotificationHelper.java +++ b/src/android/NotificationHelper.java @@ -1,5 +1,6 @@ package edu.berkeley.eecs.emission.cordova.unifiedlogger; +import android.annotation.TargetApi; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; @@ -16,11 +17,15 @@ import edu.berkeley.eecs.emission.MainActivity; import edu.berkeley.eecs.emission.R; + import java.util.List; public class NotificationHelper { private static String TAG = "NotificationHelper"; + private static String DEFAULT_CHANNEL_ID = "emissionPluginChannel"; + private static String DEFAULT_CHANNEL_DESCRIPTION = "common channel used by all e-mission native plugins"; + public static final String DISPLAY_RESOLUTION_ACTION = "DISPLAY_RESOLUTION"; public static final String RESOLUTION_PENDING_INTENT_KEY = "rpIntentKey"; public static void createNotification(Context context, int id, String message) { @@ -48,25 +53,29 @@ public static void createNotification(Context context, int id, String message) { nMgr.notify(id, builder.build()); } - /* - * Used to show a pending intent - e.g. to turn on location services - */ public static void createNotification(Context context, int id, String message, PendingIntent intent) { NotificationManager nMgr = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); Notification.Builder builder = getNotificationBuilderForApp(context, nMgr, message); + builder.setContentIntent(intent); + + Log.d(context, TAG, "Generating notify with id " + id + ", message " + message + + " and pending intent " + intent); + nMgr.notify(id, builder.build()); + } /* - * This is a bit of magic voodoo. The tutorial on launching the activity actually uses a stackbuilder - * to create a fake stack for the new activity. However, it looks like the stackbuilder - * is only available in more recent versions of the API. So I use the version for a special activity PendingIntent - * (since our app currently has only one activity) which resolves that issue. - * This also appears to work, at least in the emulator. - * - * TODO: Decide what level API we want to support, and whether we want a more comprehensive activity. + * Used to show a resolution - e.g. to turn on location services */ + public static void createResolveNotification(Context context, int id, String message, PendingIntent intent) { + NotificationManager nMgr = + (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); + + Notification.Builder builder = getNotificationBuilderForApp(context, nMgr, message); + Intent activityIntent = new Intent(context, MainActivity.class); + activityIntent.setAction(DISPLAY_RESOLUTION_ACTION); activityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); activityIntent.putExtra(NotificationHelper.RESOLUTION_PENDING_INTENT_KEY, intent); @@ -93,13 +102,8 @@ public static Notification.Builder getNotificationBuilderForApp(Context context, String message) { Notification.Builder builder = null; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - List channels = nMgr.getNotificationChannels(); - String channelID; - if (channels.size() < 1) { - throw new AssertionError("Did not find any channels, no notifications will be generated"); - } - channelID = channels.get(0).getId(); - builder = new Notification.Builder(context, channelID); + createDefaultNotificationChannelIfNeeded(context); + builder = new Notification.Builder(context, DEFAULT_CHANNEL_ID); } else { builder = new Notification.Builder(context); } @@ -111,4 +115,28 @@ public static Notification.Builder getNotificationBuilderForApp(Context context, return builder; } + + @TargetApi(26) + private static void createDefaultNotificationChannelIfNeeded(final Context ctxt) { + // only call on Android O and above + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + final NotificationManager notificationManager = (NotificationManager) ctxt.getSystemService(Context.NOTIFICATION_SERVICE); + List channels = notificationManager.getNotificationChannels(); + + for (int i = 0; i < channels.size(); i++) { + String id = channels.get(i).getId(); + Log.d(ctxt, TAG, "Checking channel with id = "+id); + if (DEFAULT_CHANNEL_ID.equals(id)) { + Log.d(ctxt, TAG, "Default channel found, returning"); + return; + } + } + + Log.d(ctxt, TAG, "Default channel not found, creating a new one"); + NotificationChannel dChannel = new NotificationChannel(DEFAULT_CHANNEL_ID, + DEFAULT_CHANNEL_DESCRIPTION, NotificationManager.IMPORTANCE_DEFAULT); + dChannel.enableVibration(true); + notificationManager.createNotificationChannel(dChannel); + } + } }