diff --git a/src/android/FirebasePlugin.java b/src/android/FirebasePlugin.java index 72475e21a..32efdb78a 100755 --- a/src/android/FirebasePlugin.java +++ b/src/android/FirebasePlugin.java @@ -73,6 +73,7 @@ public class FirebasePlugin extends CordovaPlugin { private static ArrayList notificationStack = null; private static CallbackContext notificationCallbackContext; private static CallbackContext tokenRefreshCallbackContext; + private static CallbackContext notificationMarkAsReadCallbackContext; @Override protected void pluginInitialize() { @@ -134,6 +135,9 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo } else if (action.equals("onNotificationOpen")) { this.onNotificationOpen(callbackContext); return true; + } else if (action.equals("onNotificationMarkAsRead")) { + this.onNotificationMarkAsRead(callbackContext); + return true; } else if (action.equals("onTokenRefresh")) { this.onTokenRefresh(callbackContext); return true; @@ -205,14 +209,17 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo this.setAnalyticsCollectionEnabled(callbackContext, args.getBoolean(0)); return true; } else if (action.equals("setPerformanceCollectionEnabled")) { - this.setPerformanceCollectionEnabled(callbackContext, args.getBoolean(0)); - return true; + this.setPerformanceCollectionEnabled(callbackContext, args.getBoolean(0)); + return true; } else if (action.equals("clearAllNotifications")) { this.clearAllNotifications(callbackContext); return true; } else if (action.equals("clear")) { this.clear(callbackContext, args.getInt(0)); return true; + } else if (action.equals("scheduleLocalNotification")) { + this.scheduleLocalNotification(callbackContext, args.getJSONObject(0)); + return true; } return false; @@ -232,6 +239,7 @@ public void onResume(boolean multitasking) { public void onReset() { FirebasePlugin.notificationCallbackContext = null; FirebasePlugin.tokenRefreshCallbackContext = null; + FirebasePlugin.notificationMarkAsReadCallbackContext = null; } @Override @@ -299,6 +307,10 @@ private void onNotificationOpen(final CallbackContext callbackContext) { } } + private void onNotificationMarkAsRead(final CallbackContext callbackContext) { + FirebasePlugin.notificationMarkAsReadCallbackContext = callbackContext; + } + private void onTokenRefresh(final CallbackContext callbackContext) { FirebasePlugin.tokenRefreshCallbackContext = callbackContext; @@ -351,6 +363,32 @@ public static void sendNotification(Bundle bundle, Context context) { } } + public static void sendNotificationMarkAsRead(Bundle bundle) { + final CallbackContext callbackContext = FirebasePlugin.notificationMarkAsReadCallbackContext; + + if(callbackContext == null || bundle == null){ + return; + } + + JSONObject json = new JSONObject(); + Set keys = bundle.keySet(); + for (String key : keys) { + try { + json.put(key, bundle.get(key)); + } catch (JSONException e) { + if(FirebasePlugin.crashlyticsInit()){ + Crashlytics.logException(e); + } + callbackContext.error(e.getMessage()); + return; + } + } + + PluginResult pluginresult = new PluginResult(PluginResult.Status.OK, json); + pluginresult.setKeepCallback(true); + callbackContext.sendPluginResult(pluginresult); + } + public static void sendToken(String token) { if (FirebasePlugin.tokenRefreshCallbackContext == null) { return; @@ -384,6 +422,10 @@ public static boolean hasNotificationsCallback() { return FirebasePlugin.notificationCallbackContext != null; } + public static boolean hasNotificationsMarkAsReadCallback() { + return FirebasePlugin.notificationMarkAsReadCallbackContext != null; + } + @Override public void onNewIntent(Intent intent) { super.onNewIntent(intent); @@ -1124,4 +1166,34 @@ public void run() { } }); } + + public void scheduleLocalNotification(final CallbackContext callbackContext, final JSONObject params) { + cordova.getThreadPool().execute(new Runnable() { + public void run() { + try { + Context activityContext = cordova.getActivity(); + Context appContext = activityContext.getApplicationContext(); + + String id = params.getString("id"); + String target = params.getString("target"); + String username = params.getString("username"); + String groupName = params.getString("groupName"); + String message = params.getString("message"); + String eventType = params.getString("eventType"); + String nsound = params.getString("nsound"); + String sound = params.getString("sound"); + String lights = params.getString("lights"); + + FirebasePluginMessagingService.displayNotification(activityContext, appContext, id, target, username, groupName, message, eventType, nsound, true, sound, lights); + + callbackContext.success(); + } catch (Exception e) { + if(FirebasePlugin.crashlyticsInit()){ + Crashlytics.log(e.getMessage()); + } + callbackContext.error(e.getMessage()); + } + } + }); + } } diff --git a/src/android/FirebasePluginMessagingService.java b/src/android/FirebasePluginMessagingService.java index 6b47f18f6..44766d2f7 100755 --- a/src/android/FirebasePluginMessagingService.java +++ b/src/android/FirebasePluginMessagingService.java @@ -1,24 +1,24 @@ package org.apache.cordova.firebase; +import android.app.Notification; import android.app.NotificationChannel; - import android.app.NotificationManager; import android.app.PendingIntent; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; -import android.preference.PreferenceManager; +import android.graphics.Color; import android.media.RingtoneManager; import android.net.Uri; import android.os.Build; import android.os.Bundle; +import android.preference.PreferenceManager; +import android.service.notification.StatusBarNotification; import android.support.v4.app.NotificationCompat; import android.support.v4.app.RemoteInput; -import android.util.Log; -import android.app.Notification; import android.text.TextUtils; -import android.content.ContentResolver; -import android.graphics.Color; +import android.util.Log; import com.google.firebase.messaging.FirebaseMessagingService; import com.google.firebase.messaging.RemoteMessage; @@ -34,9 +34,10 @@ import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; - +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import java.util.Map; -import java.util.Random; public class FirebasePluginMessagingService extends FirebaseMessagingService { @@ -49,10 +50,19 @@ public class FirebasePluginMessagingService extends FirebaseMessagingService { private static final String VNC_PEER_JID = "vncPeerJid"; private static final String NOTIFY_ID = "id"; - private String getStringResource(String name) { - return this.getString( - this.getResources().getIdentifier( - name, "string", this.getPackageName() + private static final String PREVIOUS_MESSAGES = "previousMessages"; + private static final String NOTIFY_ID_FOR_UPDATING = "notifIdForUpdating"; + private static final String MESSAGE_TARGET = "messageTarget"; + + private static final String AUDIO_FORMAT = "\uD83D\uDCFC Audio"; + private static final String VOICE_FORMAT = "\uD83C\uDF99 Voice Message"; + private static final String PHOTO_FORMAT = "\uD83D\uDCF7 Photo"; + private static final String LINK_FORMAT = "\uD83D\uDD17 Link"; + + private static String getStringResource(Context activityOrServiceContext, String name) { + return activityOrServiceContext.getString( + activityOrServiceContext.getResources().getIdentifier( + name, "string", activityOrServiceContext.getPackageName() ) ); } @@ -69,28 +79,6 @@ public void onMessageReceived(RemoteMessage remoteMessage) { return; } - File file = new File(this.getFilesDir(), FILE_NAME); - - FileReader fileReader = null; - FileWriter fileWriter = null; - BufferedReader bufferedReader = null; - BufferedWriter bufferedWriter = null; - - String response = null; - - if (!file.exists()) { - try { - file.createNewFile(); - fileWriter = new FileWriter(file.getAbsoluteFile()); - bufferedWriter = new BufferedWriter(fileWriter); - bufferedWriter.write("{}"); - bufferedWriter.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - - // [START_EXCLUDE] // There are two types of messages data messages and notification messages. Data messages are handled // here in onMessageReceived whether the app is in the foreground or background. Data messages are the type @@ -116,15 +104,12 @@ public void onMessageReceived(RemoteMessage remoteMessage) { data = new JSONArray(payload.get("vnc")); if (data == null || data.length() == 0) { - Log.d(TAG, "received empty data?"); + Log.d(TAG, "received empty data?"); return; } for (int i = 0; i < data.length(); i++) { Payload notification = new Gson().fromJson(data.get(i).toString(), Payload.class); - Random rand = new Random(); - int n = rand.nextInt(1000) + 1; - String id = Integer.toString(n); String target = notification.jid; String username = notification.name; String groupName = notification.gt; @@ -132,138 +117,186 @@ public void onMessageReceived(RemoteMessage remoteMessage) { String eventType = notification.eType; String nsound = notification.nsound; - Log.d(TAG, "Notification id: " + id); - Log.d(TAG, "Notification Target: " + target); - Log.d(TAG, "Notification username: " + username); - Log.d(TAG, "Notification groupName: " + groupName); - Log.d(TAG, "Notification message: " + message); - Log.d(TAG, "Notification eventType: " + eventType); - Log.d(TAG, "Notification nsound: " + nsound); - if (TextUtils.isEmpty(target) || TextUtils.isEmpty(username)) { - Log.d(TAG, "returning due to empty values"); + Log.d(TAG, "returning due to empty 'target' or 'username' values"); return; } boolean showNotification = (FirebasePlugin.inBackground() || !FirebasePlugin.hasNotificationsCallback()); - sendNotification(id, target, username, groupName, message, eventType, nsound, showNotification, "", ""); + displayNotification(this, getApplicationContext(), "0", target, username, groupName, message, eventType, nsound, showNotification, "", ""); + } + } catch (JSONException e) { + e.printStackTrace(); + return; + } + } - try { - StringBuffer output = new StringBuffer(); - fileReader = new FileReader(file.getAbsolutePath()); - bufferedReader = new BufferedReader(fileReader); + private static void saveNotificationsIdInFile(Context activityOrServiceContext, String target, Integer nId) { + File file = new File(activityOrServiceContext.getFilesDir(), FILE_NAME); - String line = ""; + FileWriter fileWriter; - while ((line = bufferedReader.readLine()) != null) { - output.append(line + "\n"); - } + // create file if does nto exist + if (!file.exists()) { + try { + file.createNewFile(); + fileWriter = new FileWriter(file.getAbsoluteFile()); + BufferedWriter bufferedWriter = new BufferedWriter(fileWriter); + bufferedWriter.write("{}"); + bufferedWriter.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } - response = output.toString(); - bufferedReader.close(); + try { + // read file into string + String response = readNotificationsFile(file); + if (response == null) { + return; + } - JSONObject messageDetails = new JSONObject(response); - Boolean isUserExisting = messageDetails.has(target); + String nIdString = String.valueOf(nId); - if (isUserExisting) { - JSONArray userMessages = (JSONArray) messageDetails.get(target); - userMessages.put(id); - } else { - JSONArray newUserMessages = new JSONArray(); - newUserMessages.put(id); - messageDetails.put(target, newUserMessages); - } + // parse file content + JSONObject messageDetails = new JSONObject(response); + + // put notification id + Boolean isConversationExisting = messageDetails.has(target); + if (isConversationExisting) { + JSONArray userMessages = (JSONArray) messageDetails.get(target); - fileWriter = new FileWriter(file.getAbsoluteFile()); - BufferedWriter bw = new BufferedWriter(fileWriter); - bw.write(messageDetails.toString()); - bw.close(); - } catch (IOException e) { - e.printStackTrace(); - } catch (JSONException e) { - e.printStackTrace(); + boolean idAlreadyExists = false; + for (int i = 0; i < userMessages.length(); i++) { + if (userMessages.get(i).toString().equals(nIdString)) { + idAlreadyExists = true; + break; + } } + if (!idAlreadyExists) { + userMessages.put(nIdString); + } + } else { + JSONArray newUserMessages = new JSONArray(); + newUserMessages.put(nIdString); + messageDetails.put(target, newUserMessages); } + // save file + fileWriter = new FileWriter(file.getAbsoluteFile()); + BufferedWriter bw = new BufferedWriter(fileWriter); + bw.write(messageDetails.toString()); + bw.close(); + } catch (IOException e) { + e.printStackTrace(); } catch (JSONException e) { e.printStackTrace(); - return; } } - private void sendNotification(String id, String target, String name, String groupName, String message, String eventType, String nosound, boolean showNotification, String sound, String lights) { - if (!showNotification) { - return; + public static ArrayList removeFromFileAndHideNotificationsForTarget(Context activityOrServiceContext, String target) { + File file = new File(activityOrServiceContext.getFilesDir(), FILE_NAME); + + // create file if does nto exist + if (!file.exists()) { + return null; } - Integer notificationId = Integer.parseInt(id); + ArrayList nIds = null; - String inlineReplyActionName = NOTIFICATION_REPLY + "@@" + id + "@@" + target; - String markAsReadActionName = MARK_AS_READ_REPLY + "@@" + id + "@@" + target; - // - PendingIntent replyPendingIntent; - PendingIntent markAsReadPendingIntent; - // - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { - Log.i("VNC", "Create notification actions (>=N), NOTIFY_ID: " + id); + try { + // read file into string + String response = readNotificationsFile(file); + if (response == null) { + return null; + } - replyPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), - REQUEST_CODE_HELP, - new Intent(this, NotificationReceiver.class) - .setAction(inlineReplyActionName), - 0); + // parse file content + JSONObject messageDetails = new JSONObject(response); - markAsReadPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), - REQUEST_CODE_HELP, - new Intent(this, NotificationReceiver.class) - .setAction(markAsReadActionName), - 0); - } else { - Log.i("VNC", "Create notification actions, NOTIFY_ID: " + id); + // remove notification ids + Boolean isConversationExisting = messageDetails.has(target); + if (isConversationExisting) { + nIds = new ArrayList(); - replyPendingIntent = PendingIntent.getActivity(getApplicationContext(), - REQUEST_CODE_HELP, - new Intent(this, ReplyActivity.class) - .setAction(inlineReplyActionName), - 0); + // collect notifications ids + JSONArray userMessages = (JSONArray) messageDetails.get(target); + for (int i = 0; i < userMessages.length(); i++) { + nIds.add(userMessages.getString(i)); + } - markAsReadPendingIntent = PendingIntent.getActivity(getApplicationContext(), - REQUEST_CODE_HELP, - new Intent(this, ReplyActivity.class) - .setAction(markAsReadActionName), - 0); + // remove + messageDetails.remove(target); + + // save file + FileWriter fileWriter = new FileWriter(file.getAbsoluteFile()); + BufferedWriter bw = new BufferedWriter(fileWriter); + bw.write(messageDetails.toString()); + bw.close(); + } + } catch (IOException e) { + e.printStackTrace(); + } catch (JSONException e) { + e.printStackTrace(); } - NotificationCompat.Action actionReply = new NotificationCompat.Action.Builder( - android.R.drawable.ic_menu_revert, "Reply", replyPendingIntent) - .addRemoteInput(new RemoteInput.Builder("Reply") - .setLabel("Type your message").build()) - .setAllowGeneratedReplies(true) - .build(); + return nIds; + } - NotificationCompat.Action actionMarkAsRead = new NotificationCompat.Action.Builder( - android.R.drawable.ic_menu_revert, "Mark as read", markAsReadPendingIntent) - .build(); + private static String readNotificationsFile(File file) { + String response = null; + try { + // read file into string + StringBuffer output = new StringBuffer(); + FileReader fileReader = new FileReader(file.getAbsolutePath()); + BufferedReader bufferedReader = new BufferedReader(fileReader); + String line = ""; + while ((line = bufferedReader.readLine()) != null) { + output.append(line + "\n"); + } + response = output.toString(); + bufferedReader.close(); + } catch (IOException e) { + e.printStackTrace(); + } - Log.d(TAG, "going to show notification with " + nosound); + return response; + } - Intent intent = new Intent(this, OnNotificationOpenReceiver.class); - Bundle bundle = new Bundle(); - bundle.putString(VNC_PEER_JID, target); - bundle.putString("vncEventType", "chat"); - bundle.putInt(NOTIFY_ID, notificationId); - intent.putExtras(bundle); - PendingIntent pendingIntent = PendingIntent.getBroadcast(this, Integer.parseInt(id), intent, PendingIntent.FLAG_UPDATE_CURRENT); + public static void displayNotification(Context activityOrServiceContext, Context appContext, String id, String target, String name, String groupName, String message, String eventType, String nsound, boolean showNotification, String sound, String lights) { + Log.i(TAG, "displayNotification: Target: " + target); + Log.i(TAG, "displayNotification: username: " + name); + Log.i(TAG, "displayNotification: groupName: " + groupName); + Log.i(TAG, "displayNotification: message: " + message); + Log.i(TAG, "displayNotification: eventType: " + eventType); + Log.i(TAG, "displayNotification: nsound: " + nsound); + Log.i(TAG, "displayNotification: showNotification: " + showNotification); + Log.i(TAG, "displayNotification: sound: " + sound); + Log.i(TAG, "displayNotification: lights: " + lights); + + if (!showNotification) { + return; + } - String channelId = this.getStringResource("default_notification_channel_id"); - String channelName = this.getStringResource("default_notification_channel_name"); + Integer notificationId = Integer.valueOf(id); + if (notificationId == 0) { + notificationId = target.hashCode(); + } + + Log.i(TAG, "displayNotification: id: " + notificationId); + + String channelId = getStringResource(activityOrServiceContext, "default_notification_channel_id"); + String channelName = getStringResource(activityOrServiceContext, "default_notification_channel_name"); Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); - if (nosound.equals("mute")) { - Log.d(TAG, "notification nosound - switching channel"); - channelId = this.getStringResource("silent_notification_channel_id"); - channelName = this.getStringResource("silent_notification_channel_name"); + if (nsound.equals("mute")) { + Log.d(TAG, "notification nsound - switching channel"); + channelId = getStringResource(activityOrServiceContext, "silent_notification_channel_id"); + channelName = getStringResource(activityOrServiceContext, "silent_notification_channel_name"); defaultSoundUri = null; } + String typeOfLink = getTypeOfLink(message); + message = typeOfLink == null ? message : typeOfLink; + String title; String text; if (eventType.equals("chat")) { @@ -272,24 +305,77 @@ private void sendNotification(String id, String target, String name, String grou } else { title = groupName != null && groupName.length() > 0 ? groupName : target; text = name; - if(message != null && message.trim().length() > 0) { + if (message != null && message.trim().length() > 0) { text = text + " : " + message; } } - Log.d(TAG, "Notification group name: " + title); + Log.d(TAG, "Notification title: " + title); + + //////////////////////////////////////////////////////////////////////////////////// + // Find previous messages and update notification ID + //////////////////////////////////////////////////////////////////////////////////// + StatusBarNotification[] activeToasts = new StatusBarNotification[0]; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { + activeToasts = ((NotificationManager) appContext.getSystemService(Context.NOTIFICATION_SERVICE)).getActiveNotifications(); + } + List msgs = new ArrayList(); + int count = 0; + for (StatusBarNotification sbn : activeToasts) { + count++; + Notification curNotif = sbn.getNotification(); + Bundle bundle = curNotif.extras; + String currentTitle = bundle.getCharSequence(Notification.EXTRA_TITLE).toString(); + String currentText = bundle.getCharSequence(Notification.EXTRA_TEXT).toString(); + String currentTarget = bundle.getString(MESSAGE_TARGET); + List previousMessages = sbn.getNotification().extras.getStringArrayList(PREVIOUS_MESSAGES); + + Log.i("vnc", "NOTIFICATION " + count + " : = " + currentTitle + " : " + currentTarget + " : " + + currentText + " : " + previousMessages + ". Message: " + message); + + if (currentTarget != null && currentTarget.equals(target)) { + notificationId = sbn.getNotification().extras.getInt(NOTIFY_ID_FOR_UPDATING); + msgs.addAll(previousMessages); + break; + } + } + if (count == 0) { + Log.i("vnc", "no notifications in Status bar, when message: " + message); + } + msgs.add(text); + + NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(activityOrServiceContext, channelId); - NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, channelId); + NotificationCompat.MessagingStyle messagingStyle = new NotificationCompat.MessagingStyle(null); + // + if (android.os.Build.VERSION.SDK_INT <= android.os.Build.VERSION_CODES.O) { + messagingStyle.setConversationTitle(title); + } + // + for (String msg : msgs) { + if (android.os.Build.VERSION.SDK_INT <= android.os.Build.VERSION_CODES.O) { + messagingStyle.addMessage(msg, System.currentTimeMillis(), null); + }else{ + messagingStyle.addMessage(msg, System.currentTimeMillis(), title); + } + } - if (nosound.equals("mute")) { - Log.d(TAG, "notification nosound: " + title); + Intent intent = new Intent(activityOrServiceContext, OnNotificationOpenReceiver.class); + Bundle bundle = new Bundle(); + bundle.putString(VNC_PEER_JID, target); + bundle.putString("vncEventType", "chat"); + bundle.putInt(NOTIFY_ID, notificationId); + intent.putExtras(bundle); + PendingIntent pendingIntent = PendingIntent.getBroadcast(activityOrServiceContext, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT); + if (nsound.equals("mute")) { + Log.d(TAG, "notification nsound: " + title); notificationBuilder .setDefaults(NotificationCompat.DEFAULT_VIBRATE) .setContentTitle(title) .setContentText(text) .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) - .setStyle(new NotificationCompat.BigTextStyle().bigText(text)) + .setStyle(messagingStyle) .setAutoCancel(true) .setShowWhen(true) .setContentIntent(pendingIntent) @@ -303,7 +389,7 @@ private void sendNotification(String id, String target, String name, String grou .setContentTitle(title) .setContentText(text) .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) - .setStyle(new NotificationCompat.BigTextStyle().bigText(text)) + .setStyle(messagingStyle) .setAutoCancel(true) .setShowWhen(true) .setContentIntent(pendingIntent) @@ -312,24 +398,74 @@ private void sendNotification(String id, String target, String name, String grou .setPriority(NotificationCompat.PRIORITY_MAX); } + // Add actions + // + String notificationIdString = String.valueOf(notificationId); + String inlineReplyActionName = NOTIFICATION_REPLY + "@@" + notificationIdString + "@@" + target; + String markAsReadActionName = MARK_AS_READ_REPLY + "@@" + notificationIdString + "@@" + target; + // + PendingIntent replyPendingIntent; + PendingIntent markAsReadPendingIntent; + // + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + Log.i("VNC", "Create notification actions (>=N), NOTIFY_ID: " + id); + + replyPendingIntent = PendingIntent.getBroadcast(appContext, + REQUEST_CODE_HELP, + new Intent(activityOrServiceContext, NotificationReceiver.class) + .setAction(inlineReplyActionName), + 0); + + markAsReadPendingIntent = PendingIntent.getBroadcast(appContext, + REQUEST_CODE_HELP, + new Intent(activityOrServiceContext, NotificationReceiver.class) + .setAction(markAsReadActionName), + 0); + } else { + Log.i("VNC", "Create notification actions, NOTIFY_ID: " + id); + + replyPendingIntent = PendingIntent.getActivity(appContext, + REQUEST_CODE_HELP, + new Intent(activityOrServiceContext, ReplyActivity.class) + .setAction(inlineReplyActionName), + 0); + + markAsReadPendingIntent = PendingIntent.getActivity(appContext, + REQUEST_CODE_HELP, + new Intent(activityOrServiceContext, ReplyActivity.class) + .setAction(markAsReadActionName), + 0); + } + + NotificationCompat.Action actionReply = new NotificationCompat.Action.Builder( + android.R.drawable.ic_menu_revert, "Reply", replyPendingIntent) + .addRemoteInput(new RemoteInput.Builder("Reply") + .setLabel("Type your message").build()) + .setAllowGeneratedReplies(true) + .build(); + + NotificationCompat.Action actionMarkAsRead = new NotificationCompat.Action.Builder( + android.R.drawable.ic_menu_revert, "Mark as read", markAsReadPendingIntent) + .build(); + if (target != null && target.trim().length() > 0 && target.indexOf("@") != -1) { notificationBuilder.addAction(actionReply); notificationBuilder.addAction(actionMarkAsRead); } - int resID = getResources().getIdentifier("logo", "drawable", getPackageName()); + int resID = activityOrServiceContext.getResources().getIdentifier("logo", "drawable", activityOrServiceContext.getPackageName()); if (resID != 0) { notificationBuilder.setSmallIcon(resID); } else { - notificationBuilder.setSmallIcon(getApplicationInfo().icon); + notificationBuilder.setSmallIcon(activityOrServiceContext.getApplicationInfo().icon); } - if (nosound.equals("mute")) { + if (nsound.equals("mute")) { Log.d(TAG, "not setting sound"); } else { if (sound != null) { Log.d(TAG, "sound before path is: " + sound); - Uri soundPath = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + getPackageName() + "/raw/" + sound); + Uri soundPath = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + activityOrServiceContext.getPackageName() + "/raw/" + sound); Log.d(TAG, "Parsed sound is: " + soundPath.toString()); notificationBuilder.setSound(soundPath); } else { @@ -352,24 +488,29 @@ private void sendNotification(String id, String target, String name, String grou } if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { - int accentID = getResources().getIdentifier("accent", "color", getPackageName()); - notificationBuilder.setColor(getResources().getColor(accentID, null)); + int accentID = activityOrServiceContext.getResources().getIdentifier("accent", "color", activityOrServiceContext.getPackageName()); + notificationBuilder.setColor(activityOrServiceContext.getResources().getColor(accentID, null)); } Notification notification = notificationBuilder.build(); + + notification.extras.putStringArrayList(PREVIOUS_MESSAGES, (ArrayList) msgs); + notification.extras.putInt(NOTIFY_ID_FOR_UPDATING, notificationId); + notification.extras.putString(MESSAGE_TARGET, target); + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { int iconID = android.R.id.icon; - int notiID = getResources().getIdentifier("icon" + - "", "mipmap", getPackageName()); + int notiID = activityOrServiceContext.getResources().getIdentifier("icon" + + "", "mipmap", activityOrServiceContext.getPackageName()); if (notification.contentView != null) { notification.contentView.setImageViewResource(iconID, notiID); } } - NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + NotificationManager notificationManager = (NotificationManager) activityOrServiceContext.getSystemService(Context.NOTIFICATION_SERVICE); // Since android Oreo notification channel is needed. if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { - if (nosound.equals("mute")) { + if (nsound.equals("mute")) { Log.d(TAG, "pushing to silentchannel"); NotificationChannel silentchannel = new NotificationChannel(channelId, channelName, NotificationManager.IMPORTANCE_HIGH); silentchannel.setSound(null, null); @@ -381,6 +522,37 @@ private void sendNotification(String id, String target, String name, String grou } notificationManager.notify(notificationId, notification); + + saveNotificationsIdInFile(activityOrServiceContext, target, notificationId); + } + + private static String getTypeOfLink(String text) { + if (text == null || text.isEmpty()) { + return null; + } + text = text.trim(); + if (!text.startsWith("http") && !text.startsWith("https")) { + return null; + } + + List photoFormat = Arrays.asList("jpg", "jpeg", "png", "gif", "bmp"); + List audioFormat = Arrays.asList("wav", "mp3", "wma", "webm", "ogg"); + + if (text.contains("audio_recording_")) { + return VOICE_FORMAT; + } + + String extension = text.substring(text.lastIndexOf(".") + 1); + + if (photoFormat.indexOf(extension) != -1) { + return PHOTO_FORMAT; + } + + if (audioFormat.indexOf(extension) != -1) { + return AUDIO_FORMAT; + } + + return LINK_FORMAT; } @@ -388,14 +560,14 @@ private String getPreference(Context context, String key) { SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context); return settings.getString(key, null); } -} -class Payload { - public String jid; - public String name; - public String eType; - public String body; - public String gt; - public String nType; - public String nsound; + class Payload { + public String jid; + public String name; + public String eType; + public String body; + public String gt; + public String nType; + public String nsound; + } } diff --git a/src/android/HttpPost.java b/src/android/HttpPost.java index 461c019b3..c8e928eb6 100644 --- a/src/android/HttpPost.java +++ b/src/android/HttpPost.java @@ -6,7 +6,7 @@ import android.preference.PreferenceManager; import android.support.v4.app.NotificationCompat; import android.util.Log; - +import android.os.Bundle; import org.json.JSONObject; import com.google.gson.Gson; @@ -18,6 +18,7 @@ import java.net.HttpURLConnection; import java.net.URL; import java.util.Date; +import java.util.ArrayList; class HttpPost implements Runnable { private String body; @@ -139,6 +140,20 @@ public void run() { this.saveMarkAsReadOnError(context, sender); } notificationManager.cancel(notificationId); + } finally { + if(requestType == RequestType.MARK_AS_READ){ + // hide all other notifications for this target + ArrayList nIds = FirebasePluginMessagingService.removeFromFileAndHideNotificationsForTarget(context, sender); + if(nIds != null){ + for (int i=0; i 0) { - Thread thread = new Thread(new HttpPost(message.toString(), sender, notificationId, context)); + Thread thread = new Thread(new HttpPost(message.toString(), target, notificationId, context)); thread.start(); } }else if (intent.getAction().contains(MARK_AS_READ_REPLY)) { String[] actionParts = intent.getAction().split("@@"); int notificationId = Integer.parseInt(actionParts[1]); - String sender = actionParts[2]; + String target = actionParts[2]; - Log.i("VNC", "NotificationReceiver onReceive MarkAsReadReply, notificationId: " + notificationId + ", sender: " + sender); + Log.i("VNC", "NotificationReceiver onReceive MarkAsReadReply, notificationId: " + notificationId + ", target: " + target); - Thread thread = new Thread(new HttpPost(sender, notificationId, context)); + Thread thread = new Thread(new HttpPost(target, notificationId, context)); thread.start(); } } diff --git a/www/firebase.js b/www/firebase.js index 99d647971..963bf7f59 100644 --- a/www/firebase.js +++ b/www/firebase.js @@ -32,6 +32,10 @@ exports.onNotificationOpen = function (success, error) { exec(success, error, "FirebasePlugin", "onNotificationOpen", []); }; +exports.onNotificationMarkAsRead = function (success, error) { + exec(success, error, "FirebasePlugin", "onNotificationMarkAsRead", []); +}; + exports.onTokenRefresh = function (success, error) { exec(success, error, "FirebasePlugin", "onTokenRefresh", []); }; @@ -179,3 +183,7 @@ exports.clearAllNotifications = function (success, error) { exports.clear = function (id, success, error) { exec(success, error, "FirebasePlugin", "clear", [id]); }; + +exports.scheduleLocalNotification = function (params, success, error) { + exec(success, error, "FirebasePlugin", "scheduleLocalNotification", [params]); +};