[notifications] WIP Android implementation
This commit is contained in:
parent
804a8e4c65
commit
99b4b6550b
|
@ -43,255 +43,7 @@ public class RNFirebaseLocalMessagingHelper {
|
|||
}
|
||||
|
||||
public void sendNotification(Bundle bundle) {
|
||||
try {
|
||||
Class intentClass = getMainActivityClass();
|
||||
if (intentClass == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (bundle.getString("body") == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Resources res = mContext.getResources();
|
||||
String packageName = mContext.getPackageName();
|
||||
|
||||
String title = bundle.getString("title");
|
||||
if (title == null) {
|
||||
ApplicationInfo appInfo = mContext.getApplicationInfo();
|
||||
title = mContext.getPackageManager().getApplicationLabel(appInfo).toString();
|
||||
}
|
||||
|
||||
NotificationCompat.Builder notification = new NotificationCompat.Builder(mContext)
|
||||
.setContentTitle(title)
|
||||
.setContentText(bundle.getString("body"))
|
||||
.setTicker(bundle.getString("ticker"))
|
||||
.setVisibility(NotificationCompat.VISIBILITY_PRIVATE)
|
||||
.setAutoCancel(bundle.getBoolean("auto_cancel", true))
|
||||
.setNumber(bundle.getInt("number"))
|
||||
.setSubText(bundle.getString("sub_text"))
|
||||
.setGroup(bundle.getString("group"))
|
||||
.setVibrate(new long[]{0, DEFAULT_VIBRATION})
|
||||
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
|
||||
.setExtras(bundle.getBundle("data"));
|
||||
|
||||
//priority
|
||||
String priority = bundle.getString("priority", "");
|
||||
switch(priority) {
|
||||
case "min":
|
||||
notification.setPriority(NotificationCompat.PRIORITY_MIN);
|
||||
break;
|
||||
case "high":
|
||||
notification.setPriority(NotificationCompat.PRIORITY_HIGH);
|
||||
break;
|
||||
case "max":
|
||||
notification.setPriority(NotificationCompat.PRIORITY_MAX);
|
||||
break;
|
||||
default:
|
||||
notification.setPriority(NotificationCompat.PRIORITY_DEFAULT);
|
||||
}
|
||||
|
||||
//icon
|
||||
String smallIcon = bundle.getString("icon", "ic_launcher");
|
||||
int smallIconResId = res.getIdentifier(smallIcon, "mipmap", packageName);
|
||||
notification.setSmallIcon(smallIconResId);
|
||||
|
||||
//large icon
|
||||
String largeIcon = bundle.getString("large_icon");
|
||||
if(largeIcon != null && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP){
|
||||
if (largeIcon.startsWith("http://") || largeIcon.startsWith("https://")) {
|
||||
Bitmap bitmap = getBitmapFromURL(largeIcon);
|
||||
notification.setLargeIcon(bitmap);
|
||||
} else {
|
||||
int largeIconResId = res.getIdentifier(largeIcon, "mipmap", packageName);
|
||||
Bitmap largeIconBitmap = BitmapFactory.decodeResource(res, largeIconResId);
|
||||
|
||||
if (largeIconResId != 0) {
|
||||
notification.setLargeIcon(largeIconBitmap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//big text
|
||||
String bigText = bundle.getString("big_text");
|
||||
if(bigText != null){
|
||||
notification.setStyle(new NotificationCompat.BigTextStyle().bigText(bigText));
|
||||
}
|
||||
|
||||
//sound
|
||||
String soundName = bundle.getString("sound", "default");
|
||||
if (!soundName.equalsIgnoreCase("default")) {
|
||||
int soundResourceId = res.getIdentifier(soundName, "raw", packageName);
|
||||
if(soundResourceId == 0){
|
||||
soundName = soundName.substring(0, soundName.lastIndexOf('.'));
|
||||
soundResourceId = res.getIdentifier(soundName, "raw", packageName);
|
||||
}
|
||||
notification.setSound(Uri.parse("android.resource://" + packageName + "/" + soundResourceId));
|
||||
}
|
||||
|
||||
//color
|
||||
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
notification.setCategory(NotificationCompat.CATEGORY_CALL);
|
||||
|
||||
String color = bundle.getString("color");
|
||||
if (color != null) {
|
||||
notification.setColor(Color.parseColor(color));
|
||||
}
|
||||
}
|
||||
|
||||
//vibrate
|
||||
if(bundle.containsKey("vibrate")){
|
||||
long vibrate = bundle.getLong("vibrate", Math.round(bundle.getDouble("vibrate", bundle.getInt("vibrate"))));
|
||||
if(vibrate > 0){
|
||||
notification.setVibrate(new long[]{0, vibrate});
|
||||
}else{
|
||||
notification.setVibrate(null);
|
||||
}
|
||||
}
|
||||
|
||||
//lights
|
||||
if (bundle.getBoolean("lights")) {
|
||||
notification.setDefaults(NotificationCompat.DEFAULT_LIGHTS);
|
||||
}
|
||||
|
||||
Log.d(TAG, "broadcast intent before showing notification");
|
||||
Intent i = new Intent("io.invertase.firebase.messaging.ReceiveLocalNotification");
|
||||
i.putExtras(bundle);
|
||||
mContext.sendOrderedBroadcast(i, null);
|
||||
|
||||
if(!mIsForeground || bundle.getBoolean("show_in_foreground")){
|
||||
Intent intent = new Intent(mContext, intentClass);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
intent.putExtras(bundle);
|
||||
intent.setAction(bundle.getString("click_action"));
|
||||
|
||||
int notificationID = bundle.containsKey("id") ? bundle.getString("id", "").hashCode() : (int) System.currentTimeMillis();
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(mContext, notificationID, intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
NotificationManager notificationManager =
|
||||
(NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
|
||||
notification.setContentIntent(pendingIntent);
|
||||
|
||||
Notification info = notification.build();
|
||||
|
||||
if (bundle.containsKey("tag")) {
|
||||
String tag = bundle.getString("tag");
|
||||
notificationManager.notify(tag, notificationID, info);
|
||||
} else {
|
||||
notificationManager.notify(notificationID, info);
|
||||
}
|
||||
}
|
||||
//clear out one time scheduled notification once fired
|
||||
if(!bundle.containsKey("repeat_interval") && bundle.containsKey("fire_date")) {
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
editor.remove(bundle.getString("id"));
|
||||
editor.apply();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "failed to send local notification", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void sendNotificationScheduled(Bundle bundle) {
|
||||
Class intentClass = getMainActivityClass();
|
||||
if (intentClass == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
String notificationId = bundle.getString("id");
|
||||
if(notificationId == null){
|
||||
Log.e(TAG, "failed to schedule notification because id is missing");
|
||||
return;
|
||||
}
|
||||
|
||||
Long fireDate = Math.round(bundle.getDouble("fire_date"));
|
||||
|
||||
if (fireDate == 0) {
|
||||
Log.e(TAG, "failed to schedule notification because fire date is missing");
|
||||
return;
|
||||
}
|
||||
|
||||
Intent notificationIntent = new Intent(mContext, RNFirebaseLocalMessagingPublisher.class);
|
||||
notificationIntent.putExtras(bundle);
|
||||
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, notificationId.hashCode(), notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
Long interval = null;
|
||||
switch (bundle.getString("repeat_interval", "")) {
|
||||
case "minute":
|
||||
interval = (long) 60000;
|
||||
break;
|
||||
case "hour":
|
||||
interval = AlarmManager.INTERVAL_HOUR;
|
||||
break;
|
||||
case "day":
|
||||
interval = AlarmManager.INTERVAL_DAY;
|
||||
break;
|
||||
case "week":
|
||||
interval = AlarmManager.INTERVAL_DAY * 7;
|
||||
break;
|
||||
}
|
||||
|
||||
if(interval != null){
|
||||
getAlarmManager().setRepeating(AlarmManager.RTC_WAKEUP, fireDate, interval, pendingIntent);
|
||||
} else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
|
||||
getAlarmManager().setExact(AlarmManager.RTC_WAKEUP, fireDate, pendingIntent);
|
||||
}else {
|
||||
getAlarmManager().set(AlarmManager.RTC_WAKEUP, fireDate, pendingIntent);
|
||||
}
|
||||
|
||||
//store intent
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
try {
|
||||
JSONObject json = BundleJSONConverter.convertToJSON(bundle);
|
||||
editor.putString(notificationId, json.toString());
|
||||
editor.apply();
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public void cancelLocalNotification(String notificationId) {
|
||||
cancelAlarm(notificationId);
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
editor.remove(notificationId);
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public void cancelAllLocalNotifications() {
|
||||
java.util.Map<String, ?> keyMap = sharedPreferences.getAll();
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
for(java.util.Map.Entry<String, ?> entry:keyMap.entrySet()){
|
||||
cancelAlarm(entry.getKey());
|
||||
}
|
||||
editor.clear();
|
||||
editor.apply();
|
||||
}
|
||||
|
||||
public void removeDeliveredNotification(String notificationId){
|
||||
NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.cancel(notificationId.hashCode());
|
||||
}
|
||||
|
||||
public void removeAllDeliveredNotifications(){
|
||||
NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.cancelAll();
|
||||
}
|
||||
|
||||
public ArrayList<Bundle> getScheduledLocalNotifications(){
|
||||
ArrayList<Bundle> array = new ArrayList<Bundle>();
|
||||
java.util.Map<String, ?> keyMap = sharedPreferences.getAll();
|
||||
for(java.util.Map.Entry<String, ?> entry:keyMap.entrySet()){
|
||||
try {
|
||||
JSONObject json = new JSONObject((String)entry.getValue());
|
||||
Bundle bundle = BundleJSONConverter.convertToBundle(json);
|
||||
array.add(bundle);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public void setApplicationForeground(boolean foreground){
|
||||
|
@ -309,28 +61,4 @@ public class RNFirebaseLocalMessagingHelper {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private AlarmManager getAlarmManager() {
|
||||
return (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
|
||||
}
|
||||
|
||||
private void cancelAlarm(String notificationId) {
|
||||
Intent notificationIntent = new Intent(mContext, RNFirebaseLocalMessagingPublisher.class);
|
||||
PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, notificationId.hashCode(), notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
getAlarmManager().cancel(pendingIntent);
|
||||
}
|
||||
|
||||
private Bitmap getBitmapFromURL(String strURL) {
|
||||
try {
|
||||
URL url = new URL(strURL);
|
||||
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
|
||||
connection.setDoInput(true);
|
||||
connection.connect();
|
||||
InputStream input = connection.getInputStream();
|
||||
return BitmapFactory.decodeStream(input);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
package io.invertase.firebase.messaging;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
public class RNFirebaseLocalMessagingPublisher extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
new RNFirebaseLocalMessagingHelper((Application) context.getApplicationContext()).sendNotification(intent.getExtras());
|
||||
}
|
||||
}
|
|
@ -34,7 +34,7 @@ public class RNFirebaseMessaging extends ReactContextBaseJavaModule implements A
|
|||
private static final String BADGE_FILE = "BadgeCountFile";
|
||||
private static final String BADGE_KEY = "BadgeCount";
|
||||
|
||||
private static final String TAG = RNFirebaseMessaging.class.getCanonicalName();
|
||||
private static final String TAG = "RNFirebaseMessaging";
|
||||
|
||||
private SharedPreferences sharedPreferences = null;
|
||||
|
||||
|
|
|
@ -1,27 +0,0 @@
|
|||
package io.invertase.firebase.messaging;
|
||||
|
||||
import android.app.Application;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Set alarms for scheduled notification after system reboot.
|
||||
*/
|
||||
public class RNFirebaseSystemBootEventReceiver extends BroadcastReceiver {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Log.i("FCMSystemBootReceiver", "Received reboot event");
|
||||
RNFirebaseLocalMessagingHelper helper = new RNFirebaseLocalMessagingHelper((Application) context.getApplicationContext());
|
||||
ArrayList<Bundle> bundles = helper.getScheduledLocalNotifications();
|
||||
for(Bundle bundle: bundles){
|
||||
helper.sendNotificationScheduled(bundle);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,434 @@
|
|||
package io.invertase.firebase.notifications;
|
||||
|
||||
|
||||
import android.app.AlarmManager;
|
||||
import android.app.Application;
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Color;
|
||||
import android.media.RingtoneManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.util.Log;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.Promise;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
|
||||
import io.invertase.firebase.messaging.BundleJSONConverter;
|
||||
|
||||
public class RNFirebaseNotificationManager {
|
||||
private static final String PREFERENCES_KEY = "RNFNotifications";
|
||||
private static final String TAG = "RNFNotificationManager";
|
||||
private AlarmManager alarmManager;
|
||||
private Context context;
|
||||
private NotificationManager notificationManager;
|
||||
private SharedPreferences preferences;
|
||||
|
||||
public RNFirebaseNotificationManager(Context context) {
|
||||
this.alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
|
||||
this.context = context;
|
||||
this.notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
this.preferences = context.getSharedPreferences(PREFERENCES_KEY, Context.MODE_PRIVATE);
|
||||
}
|
||||
|
||||
public void cancelAllNotifications() {
|
||||
try {
|
||||
Map<String, ?> notifications = preferences.getAll();
|
||||
|
||||
for(String notificationId : notifications.keySet()){
|
||||
cancelAlarm(notificationId);
|
||||
}
|
||||
preferences.edit().clear().apply();
|
||||
} catch (SecurityException e) {
|
||||
// TODO: Identify what these situations are
|
||||
// In some devices/situations cancelAllLocalNotifications can throw a SecurityException.
|
||||
Log.e(TAG, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void cancelNotification(String notificationId) {
|
||||
cancelAlarm(notificationId);
|
||||
preferences.edit().remove(notificationId).apply();
|
||||
}
|
||||
|
||||
public void displayNotification(Bundle notification) {
|
||||
displayNotification(notification, null);
|
||||
}
|
||||
|
||||
public void displayNotification(ReadableMap notification, Promise promise) {
|
||||
Bundle notificationBundle = Arguments.toBundle(notification);
|
||||
displayNotification(notificationBundle, promise);
|
||||
}
|
||||
|
||||
private void displayNotification(Bundle notification, Promise promise) {
|
||||
try {
|
||||
Class intentClass = getMainActivityClass();
|
||||
if (intentClass == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (bundle.getString("body") == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Resources res = mContext.getResources();
|
||||
String packageName = mContext.getPackageName();
|
||||
|
||||
String channelId = notification.getString("channelId");
|
||||
|
||||
NotificationCompat.Builder nb = new NotificationCompat.Builder(context, channelId);
|
||||
|
||||
if (notification.containsKey("body")) {
|
||||
nb = nb.setContentText(notification.getString("body"));
|
||||
}
|
||||
if (notification.containsKey("data")) {
|
||||
nb = nb.setExtras(notification.getBundle("data"));
|
||||
}
|
||||
if (notification.containsKey("sound")) {
|
||||
// TODO: Sound URI;
|
||||
nb = nb.setSound();
|
||||
}
|
||||
if (notification.containsKey("subtitle")) {
|
||||
nb = nb.setSubText(notification.getString("subtitle"));
|
||||
}
|
||||
if (notification.containsKey("title")) {
|
||||
nb = nb.setContentTitle(notification.getString("title"));
|
||||
}
|
||||
|
||||
if (notification.containsKey("autoCancel")) {
|
||||
nb = nb.setAutoCancel(notification.getBoolean("autoCancel"));
|
||||
}
|
||||
if (notification.containsKey("badgeIconType")) {
|
||||
nb = nb.setBadgeIconType(notification.getInt("badgeIconType"));
|
||||
}
|
||||
if (notification.containsKey("category")) {
|
||||
nb = nb.setCategory(notification.getString("category"));
|
||||
}
|
||||
if (notification.containsKey("color")) {
|
||||
nb = nb.setColor(notification.getInt("color"));
|
||||
}
|
||||
if (notification.containsKey("colorized")) {
|
||||
nb = nb.setColorized(notification.getBoolean("colorized"));
|
||||
}
|
||||
if (notification.containsKey("contentInfo")) {
|
||||
nb = nb.setContentInfo(notification.getString("contentInfo"));
|
||||
}
|
||||
if (notification.containsKey("defaults")) {
|
||||
// TODO: Bitwise ?
|
||||
nb = nb.setDefaults()
|
||||
}
|
||||
if (notification.containsKey("group")) {
|
||||
nb = nb.setGroup(notification.getString("group"));
|
||||
}
|
||||
if (notification.containsKey("groupAlertBehaviour")) {
|
||||
nb = nb.setGroupAlertBehavior(notification.getInt("groupAlertBehaviour"));
|
||||
}
|
||||
if (notification.containsKey("groupSummary")) {
|
||||
nb = nb.setGroupSummary(notification.getBoolean("groupSummary"));
|
||||
}
|
||||
if (notification.containsKey("largeIcon")) {
|
||||
Bitmap largeIcon = getBitmap(notification.getString("largeIcon"));
|
||||
if (largeIcon != null) {
|
||||
nb = nb.setLargeIcon(largeIcon);
|
||||
}
|
||||
}
|
||||
if (notification.containsKey("lights")) {
|
||||
Bundle lights = notification.getBundle("lights");
|
||||
nb = nb.setLights(lights.getInt("argb"), lights.getInt("onMs"), lights.getInt("offMs"));
|
||||
}
|
||||
if (notification.containsKey("localOnly")) {
|
||||
nb = nb.setLocalOnly(notification.getBoolean("localOnly"));
|
||||
}
|
||||
|
||||
if (notification.containsKey("number")) {
|
||||
nb = nb.setNumber(notification.getInt("number"));
|
||||
}
|
||||
if (notification.containsKey("ongoing")) {
|
||||
nb = nb.setOngoing(notification.getBoolean("ongoing"));
|
||||
}
|
||||
if (notification.containsKey("onlyAlertOnce")) {
|
||||
nb = nb.setOngoing(notification.getBoolean("onlyAlertOnce"));
|
||||
}
|
||||
if (notification.containsKey("people")) {
|
||||
String[] people = notification.getStringArray("people");
|
||||
for (String person : people) {
|
||||
nb = nb.addPerson(person);
|
||||
}
|
||||
}
|
||||
if (notification.containsKey("priority")) {
|
||||
nb = nb.setPriority(notification.getInt("priority"));
|
||||
}
|
||||
if (notification.containsKey("progress")) {
|
||||
Bundle progress = notification.getBundle("lights");
|
||||
nb = nb.setProgress(progress.getInt("max"), progress.getInt("progress"), progress.getBoolean("indeterminate"));
|
||||
}
|
||||
if (notification.containsKey("publicVersion")) {
|
||||
// TODO: Build notification
|
||||
nb = nb.setPublicVersion();
|
||||
}
|
||||
if (notification.containsKey("remoteInputHistory")) {
|
||||
// TODO: Build notification
|
||||
nb = nb.setRemoteInputHistory(notification.getStringArray("remoteInputHistory"));
|
||||
}
|
||||
if (notification.containsKey("shortcutId")) {
|
||||
nb = nb.setShortcutId(notification.getString("shortcutId"));
|
||||
}
|
||||
if (notification.containsKey("showWhen")) {
|
||||
nb = nb.setShowWhen(notification.getBoolean("showWhen"));
|
||||
}
|
||||
if (notification.containsKey("smallIcon")) {
|
||||
nb = nb.setSmallIcon(notification.getInt("smallIcon"));
|
||||
}
|
||||
if (notification.containsKey("sortKey")) {
|
||||
nb = nb.setSortKey(notification.getString("sortKey"));
|
||||
}
|
||||
if (notification.containsKey("ticker")) {
|
||||
nb = nb.setTicker(notification.getString("ticker"));
|
||||
}
|
||||
if (notification.containsKey("timeoutAfter")) {
|
||||
nb = nb.setTimeoutAfter(notification.getLong("timeoutAfter"));
|
||||
}
|
||||
if (notification.containsKey("usesChronometer")) {
|
||||
nb = nb.setUsesChronometer(notification.getBoolean("usesChronometer"));
|
||||
}
|
||||
if (notification.containsKey("vibrate")) {
|
||||
nb = nb.setVibrate(notification.getLongArray("vibrate"));
|
||||
}
|
||||
if (notification.containsKey("visibility")) {
|
||||
nb = nb.setVisibility(notification.getInt("visibility"));
|
||||
}
|
||||
if (notification.containsKey("when")) {
|
||||
nb = nb.setWhen(notification.getLong("when"));
|
||||
}
|
||||
// TODO actions: Action[]; // icon, title, ??pendingIntent??, allowGeneratedReplies, extender, extras, remoteinput (ugh)
|
||||
// TODO: style: Style; // Need to figure out if this can work
|
||||
|
||||
//icon
|
||||
String smallIcon = bundle.getString("icon", "ic_launcher");
|
||||
int smallIconResId = res.getIdentifier(smallIcon, "mipmap", packageName);
|
||||
notification.setSmallIcon(smallIconResId);
|
||||
|
||||
//big text
|
||||
String bigText = bundle.getString("big_text");
|
||||
if(bigText != null){
|
||||
notification.setStyle(new NotificationCompat.BigTextStyle().bigText(bigText));
|
||||
}
|
||||
|
||||
//sound
|
||||
String soundName = bundle.getString("sound", "default");
|
||||
if (!soundName.equalsIgnoreCase("default")) {
|
||||
int soundResourceId = res.getIdentifier(soundName, "raw", packageName);
|
||||
if(soundResourceId == 0){
|
||||
soundName = soundName.substring(0, soundName.lastIndexOf('.'));
|
||||
soundResourceId = res.getIdentifier(soundName, "raw", packageName);
|
||||
}
|
||||
notification.setSound(Uri.parse("android.resource://" + packageName + "/" + soundResourceId));
|
||||
}
|
||||
|
||||
//color
|
||||
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
String color = bundle.getString("color");
|
||||
if (color != null) {
|
||||
notification.setColor(Color.parseColor(color));
|
||||
}
|
||||
}
|
||||
|
||||
//lights
|
||||
if (bundle.getBoolean("lights")) {
|
||||
notification.setDefaults(NotificationCompat.DEFAULT_LIGHTS);
|
||||
}
|
||||
|
||||
Log.d(TAG, "broadcast intent before showing notification");
|
||||
Intent i = new Intent("io.invertase.firebase.messaging.ReceiveLocalNotification");
|
||||
i.putExtras(bundle);
|
||||
mContext.sendOrderedBroadcast(i, null);
|
||||
|
||||
if(!mIsForeground || bundle.getBoolean("show_in_foreground")){
|
||||
Intent intent = new Intent(mContext, intentClass);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
|
||||
intent.putExtras(bundle);
|
||||
intent.setAction(bundle.getString("click_action"));
|
||||
|
||||
int notificationID = bundle.containsKey("id") ? bundle.getString("id", "").hashCode() : (int) System.currentTimeMillis();
|
||||
PendingIntent pendingIntent = PendingIntent.getActivity(mContext, notificationID, intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
NotificationManager notificationManager =
|
||||
(NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
|
||||
notification.setContentIntent(pendingIntent);
|
||||
|
||||
Notification info = notification.build();
|
||||
|
||||
if (bundle.containsKey("tag")) {
|
||||
String tag = bundle.getString("tag");
|
||||
notificationManager.notify(tag, notificationID, info);
|
||||
} else {
|
||||
notificationManager.notify(notificationID, info);
|
||||
}
|
||||
}
|
||||
//clear out one time scheduled notification once fired
|
||||
if(!bundle.containsKey("repeat_interval") && bundle.containsKey("fire_date")) {
|
||||
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||
editor.remove(bundle.getString("id"));
|
||||
editor.apply();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "failed to send local notification", e);
|
||||
}
|
||||
}
|
||||
|
||||
public ArrayList<Bundle> getScheduledNotifications(){
|
||||
ArrayList<Bundle> array = new ArrayList<>();
|
||||
|
||||
Map<String, ?> notifications = preferences.getAll();
|
||||
|
||||
for(String notificationId : notifications.keySet()){
|
||||
try {
|
||||
JSONObject json = new JSONObject((String)notifications.get(notificationId));
|
||||
Bundle bundle = BundleJSONConverter.convertToBundle(json);
|
||||
array.add(bundle);
|
||||
} catch (JSONException e) {
|
||||
Log.e(TAG, e.getMessage());
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public void removeAllDeliveredNotifications() {
|
||||
notificationManager.cancelAll();
|
||||
}
|
||||
|
||||
public void removeDeliveredNotification(String notificationId) {
|
||||
notificationManager.cancel(notificationId.hashCode());
|
||||
}
|
||||
|
||||
|
||||
public void rescheduleNotifications() {
|
||||
ArrayList<Bundle> bundles = getScheduledNotifications();
|
||||
for(Bundle bundle: bundles){
|
||||
scheduleNotification(bundle, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void scheduleNotification(ReadableMap notification, ReadableMap schedule, Promise promise) {
|
||||
Bundle notificationBundle = Arguments.toBundle(notification);
|
||||
|
||||
scheduleNotification(notificationBundle, promise);
|
||||
}
|
||||
|
||||
private void scheduleNotification(Bundle notification, Promise promise) {
|
||||
// TODO
|
||||
String notificationId = notification.getString("notificationId");
|
||||
if (!notification.containsKey("notificationId")) {
|
||||
if (promise != null) {
|
||||
promise.reject("notification/schedule_notification_error", "Missing notificationId");
|
||||
} else {
|
||||
Log.e(TAG, "Missing notificationId");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Schedule check
|
||||
if (!notification.hasKey("schedule")) {
|
||||
|
||||
return;
|
||||
}
|
||||
/*
|
||||
Long fireDate = Math.round(bundle.getDouble("fire_date"));
|
||||
|
||||
if (fireDate == 0) {
|
||||
Log.e(TAG, "failed to schedule notification because fire date is missing");
|
||||
return;
|
||||
}*/
|
||||
|
||||
|
||||
// Scheduled alarms are cleared on restart
|
||||
// We store them so that they can be re-scheduled when the phone restarts in RNFirebaseNotificationsRebootReceiver
|
||||
try {
|
||||
JSONObject json = BundleJSONConverter.convertToJSON(notification);
|
||||
preferences.edit().putString(notificationId, json.toString()).apply();
|
||||
} catch (JSONException e) {
|
||||
promise.reject("notification/schedule_notification_error", "Failed to store notification", e);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Intent notificationIntent = new Intent(context, RNFirebaseNotificationReceiver.class);
|
||||
notificationIntent.putExtras(notification);
|
||||
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, notificationId.hashCode(), notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
|
||||
// TODO: Scheduling
|
||||
Long interval = null;
|
||||
switch (notification.getString("repeat_interval", "")) {
|
||||
case "minute":
|
||||
interval = (long) 60000;
|
||||
break;
|
||||
case "hour":
|
||||
interval = AlarmManager.INTERVAL_HOUR;
|
||||
break;
|
||||
case "day":
|
||||
interval = AlarmManager.INTERVAL_DAY;
|
||||
break;
|
||||
case "week":
|
||||
interval = AlarmManager.INTERVAL_DAY * 7;
|
||||
break;
|
||||
}
|
||||
|
||||
if(interval != null){
|
||||
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, fireDate, interval, pendingIntent);
|
||||
} else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){
|
||||
alarmManager.setExact(AlarmManager.RTC_WAKEUP, fireDate, pendingIntent);
|
||||
}else {
|
||||
alarmManager.set(AlarmManager.RTC_WAKEUP, fireDate, pendingIntent);
|
||||
}
|
||||
}
|
||||
|
||||
private void cancelAlarm(String notificationId) {
|
||||
Intent notificationIntent = new Intent(context, RNFirebaseNotificationManager.class);
|
||||
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, notificationId.hashCode(), notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
alarmManager.cancel(pendingIntent);
|
||||
}
|
||||
|
||||
private Bitmap getBitmap(String image) {
|
||||
if (image.startsWith("http://") || image.startsWith("https://")) {
|
||||
return getBitmapFromUrl(image);
|
||||
} else {
|
||||
int largeIconResId = res.getIdentifier(image, "mipmap", packageName);
|
||||
return BitmapFactory.decodeResource(res, largeIconResId);
|
||||
}
|
||||
}
|
||||
|
||||
private Bitmap getBitmapFromUrl(String imageUrl) {
|
||||
try {
|
||||
HttpURLConnection connection = (HttpURLConnection) new URL(imageUrl).openConnection();
|
||||
connection.setDoInput(true);
|
||||
connection.connect();
|
||||
return BitmapFactory.decodeStream(connection.getInputStream());
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package io.invertase.firebase.notifications;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
||||
/*
|
||||
* This is invoked by the Alarm Manager when it is time to display a scheduled notification.
|
||||
*/
|
||||
public class RNFirebaseNotificationReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
new RNFirebaseNotificationManager(context).displayNotification(intent.getExtras());
|
||||
}
|
||||
}
|
|
@ -1,15 +1,24 @@
|
|||
package io.invertase.firebase.notifications;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.NotificationCompat;
|
||||
import android.util.Log;
|
||||
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.Promise;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.WritableArray;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class RNFirebaseNotifications extends ReactContextBaseJavaModule {
|
||||
private RNFirebaseNotificationManager notificationManager;
|
||||
public RNFirebaseNotifications(ReactApplicationContext context) {
|
||||
super(context);
|
||||
notificationManager = new RNFirebaseNotificationManager(context.getApplicationContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -18,8 +27,47 @@ public class RNFirebaseNotifications extends ReactContextBaseJavaModule {
|
|||
}
|
||||
|
||||
@ReactMethod
|
||||
public void sendNotification(Promise promise) {
|
||||
//
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder()
|
||||
public void cancelAllNotifications() {
|
||||
notificationManager.cancelAllNotifications();
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void cancelNotification(String notificationId) {
|
||||
notificationManager.cancelNotification(notificationId);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void displayNotification(ReadableMap notification, Promise promise) {
|
||||
notificationManager.displayNotification(notification, promise);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void getInitialNotification(Promise promise) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void getScheduledNotifications(Promise promise) {
|
||||
ArrayList<Bundle> bundles = notificationManager.getScheduledNotifications();
|
||||
WritableArray array = Arguments.createArray();
|
||||
for (Bundle bundle : bundles) {
|
||||
array.pushMap(parseNotificationBundle(bundle));
|
||||
}
|
||||
promise.resolve(array);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void removeAllDeliveredNotifications() {
|
||||
notificationManager.removeAllDeliveredNotifications();
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void removeDeliveredNotification(String notificationId) {
|
||||
notificationManager.removeDeliveredNotification(notificationId);
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public void scheduleNotification(ReadableMap notification, ReadableMap schedule, Promise promise) {
|
||||
notificationManager.scheduleNotification(notification, schedule, promise);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
package io.invertase.firebase.notifications;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
|
||||
/*
|
||||
* This is invoked when the phone restarts to ensure that all notifications are rescheduled
|
||||
* correctly, as Android removes all scheduled alarms when the phone shuts down.
|
||||
*/
|
||||
public class RNFirebaseNotificationsRebootReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Log.i("RNFNotifRebootReceiver", "Received reboot event");
|
||||
new RNFirebaseNotificationManager(context).rescheduleNotifications();
|
||||
}
|
||||
}
|
|
@ -505,6 +505,11 @@ export default class AndroidNotification {
|
|||
|
||||
build(): NativeAndroidNotification {
|
||||
// TODO: Validation
|
||||
if (!this._channelId) {
|
||||
throw new Error(
|
||||
'AndroidNotification: Missing required `channelId` property'
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
// TODO actions: Action[],
|
||||
|
|
Loading…
Reference in New Issue