diff --git a/android/build.gradle b/android/build.gradle
index 6f05c1b10..dc7614327 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -20,7 +20,7 @@ android {
dependencies {
// Google's GCM.
- compile 'com.google.android.gms:play-services-gcm:10.0.1'
+ compile "com.google.firebase:firebase-messaging:10.2.6"
compile 'com.facebook.react:react-native:+'
diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml
index 143347523..e31d5a40b 100644
--- a/android/src/main/AndroidManifest.xml
+++ b/android/src/main/AndroidManifest.xml
@@ -3,14 +3,6 @@
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.wix.reactnativenotifications">
-
-
-
-
@@ -21,39 +13,22 @@
-->
-
-
-
-
-
-
-
-
+ android:name="com.wix.reactnativenotifications.fcm.FcmMessageHandlerService">
-
+
+ android:name=".fcm.FcmInstanceIdListenerService">
-
+
diff --git a/android/src/main/java/com/wix/reactnativenotifications/Defs.java b/android/src/main/java/com/wix/reactnativenotifications/Defs.java
index fff51742c..5256baa94 100644
--- a/android/src/main/java/com/wix/reactnativenotifications/Defs.java
+++ b/android/src/main/java/com/wix/reactnativenotifications/Defs.java
@@ -2,7 +2,6 @@
public interface Defs {
String LOGTAG = "ReactNativeNotifs";
- String GCM_SENDER_ID_ATTR_NAME = "com.wix.reactnativenotifications.gcmSenderId";
String TOKEN_RECEIVED_EVENT_NAME = "remoteNotificationsRegistered";
diff --git a/android/src/main/java/com/wix/reactnativenotifications/RNNotificationsModule.java b/android/src/main/java/com/wix/reactnativenotifications/RNNotificationsModule.java
index 1f5535e62..58e67faef 100644
--- a/android/src/main/java/com/wix/reactnativenotifications/RNNotificationsModule.java
+++ b/android/src/main/java/com/wix/reactnativenotifications/RNNotificationsModule.java
@@ -5,6 +5,7 @@
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
+import android.support.annotation.Nullable;
import android.util.Log;
import com.facebook.react.bridge.Arguments;
@@ -17,12 +18,12 @@
import com.wix.reactnativenotifications.core.AppLifecycleFacadeHolder;
import com.wix.reactnativenotifications.core.InitialNotificationHolder;
import com.wix.reactnativenotifications.core.ReactAppLifecycleFacade;
-import com.wix.reactnativenotifications.core.notification.IPushNotification;
-import com.wix.reactnativenotifications.core.notification.PushNotification;
-import com.wix.reactnativenotifications.core.notification.PushNotificationProps;
-import com.wix.reactnativenotifications.core.notificationdrawer.IPushNotificationsDrawer;
-import com.wix.reactnativenotifications.core.notificationdrawer.PushNotificationsDrawer;
-import com.wix.reactnativenotifications.gcm.GcmInstanceIdRefreshHandlerService;
+import com.wix.reactnativenotifications.core.notificationdrawer.INotificationDrawer;
+import com.wix.reactnativenotifications.core.notificationdrawer.NotificationDrawer;
+import com.wix.reactnativenotifications.core.notifications.ILocalNotification;
+import com.wix.reactnativenotifications.core.notifications.LocalNotification;
+import com.wix.reactnativenotifications.core.notifications.NotificationProps;
+import com.wix.reactnativenotifications.fcm.FcmTokenService;
import static com.wix.reactnativenotifications.Defs.LOGTAG;
@@ -46,16 +47,14 @@ public String getName() {
@Override
public void initialize() {
Log.d(LOGTAG, "Native module init");
- startGcmIntentService(GcmInstanceIdRefreshHandlerService.EXTRA_IS_APP_INIT);
-
- final IPushNotificationsDrawer notificationsDrawer = PushNotificationsDrawer.get(getReactApplicationContext().getApplicationContext());
+ final INotificationDrawer notificationsDrawer = NotificationDrawer.get(getReactApplicationContext().getApplicationContext());
notificationsDrawer.onAppInit();
}
@ReactMethod
public void refreshToken() {
Log.d(LOGTAG, "Native method invocation: refreshToken()");
- startGcmIntentService(GcmInstanceIdRefreshHandlerService.EXTRA_MANUAL_REFRESH);
+ startTokenService(FcmTokenService.ACTION_REFRESH_TOKEN);
}
@ReactMethod
@@ -64,7 +63,7 @@ public void getInitialNotification(final Promise promise) {
Object result = null;
try {
- final PushNotificationProps notification = InitialNotificationHolder.getInstance().get();
+ final NotificationProps notification = InitialNotificationHolder.getInstance().get();
if (notification == null) {
return;
}
@@ -76,22 +75,29 @@ public void getInitialNotification(final Promise promise) {
}
@ReactMethod
- public void postLocalNotification(ReadableMap notificationPropsMap, int notificationId) {
+ public void postLocalNotification(ReadableMap propsMap, int notificationId) {
Log.d(LOGTAG, "Native method invocation: postLocalNotification");
- final Bundle notificationProps = Arguments.toBundle(notificationPropsMap);
- final IPushNotification pushNotification = PushNotification.get(getReactApplicationContext().getApplicationContext(), notificationProps);
- pushNotification.onPostRequest(notificationId);
+ final Context context = getReactApplicationContext().getApplicationContext();
+ final NotificationProps localNotificationProps = NotificationProps.fromBundle(context, Arguments.toBundle(propsMap));
+ final ILocalNotification notification = LocalNotification.get(context, localNotificationProps);
+ notification.post(notificationId);
+ }
+
+ @ReactMethod
+ public void cancelLocalNotification(int notificationId, @Nullable String notificationTag) {
+ INotificationDrawer notificationsDrawer = NotificationDrawer.get(getReactApplicationContext().getApplicationContext());
+ notificationsDrawer.onCancelLocalNotification(notificationTag, notificationId);
}
@ReactMethod
- public void cancelLocalNotification(int notificationId) {
- IPushNotificationsDrawer notificationsDrawer = PushNotificationsDrawer.get(getReactApplicationContext().getApplicationContext());
- notificationsDrawer.onNotificationClearRequest(notificationId);
+ public void cancelAllLocalNotifications() {
+ INotificationDrawer notificationDrawer = NotificationDrawer.get(getReactApplicationContext().getApplicationContext());
+ notificationDrawer.onCancelAllLocalNotifications();
}
@Override
public void onAppVisible() {
- final IPushNotificationsDrawer notificationsDrawer = PushNotificationsDrawer.get(getReactApplicationContext().getApplicationContext());
+ final INotificationDrawer notificationsDrawer = NotificationDrawer.get(getReactApplicationContext().getApplicationContext());
notificationsDrawer.onAppVisible();
}
@@ -101,7 +107,7 @@ public void onAppNotVisible() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
- final IPushNotificationsDrawer notificationsDrawer = PushNotificationsDrawer.get(getReactApplicationContext().getApplicationContext());
+ final INotificationDrawer notificationsDrawer = NotificationDrawer.get(getReactApplicationContext().getApplicationContext());
notificationsDrawer.onNewActivity(activity);
}
@@ -129,10 +135,10 @@ public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
public void onActivityDestroyed(Activity activity) {
}
- protected void startGcmIntentService(String extraFlag) {
+ protected void startTokenService(String action) {
final Context appContext = getReactApplicationContext().getApplicationContext();
- final Intent tokenFetchIntent = new Intent(appContext, GcmInstanceIdRefreshHandlerService.class);
- tokenFetchIntent.putExtra(extraFlag, true);
- appContext.startService(tokenFetchIntent);
+ final Intent intent = new Intent(appContext, FcmTokenService.class);
+ intent.setAction(action);
+ appContext.startService(intent);
}
}
diff --git a/android/src/main/java/com/wix/reactnativenotifications/core/InitialNotificationHolder.java b/android/src/main/java/com/wix/reactnativenotifications/core/InitialNotificationHolder.java
index 3636f41f7..b257f9a2d 100644
--- a/android/src/main/java/com/wix/reactnativenotifications/core/InitialNotificationHolder.java
+++ b/android/src/main/java/com/wix/reactnativenotifications/core/InitialNotificationHolder.java
@@ -2,13 +2,13 @@
import android.support.annotation.Nullable;
-import com.wix.reactnativenotifications.core.notification.PushNotificationProps;
+import com.wix.reactnativenotifications.core.notifications.NotificationProps;
public class InitialNotificationHolder {
private static InitialNotificationHolder sInstance;
- private PushNotificationProps mNotification;
+ private NotificationProps mNotification;
public static void setInstance(InitialNotificationHolder instance) {
sInstance = instance;
@@ -24,8 +24,8 @@ public static InitialNotificationHolder getInstance() {
return sInstance;
}
- public void set(PushNotificationProps pushNotificationProps) {
- mNotification = pushNotificationProps;
+ public void set(NotificationProps notificationProps) {
+ mNotification = notificationProps;
}
public void clear() {
@@ -33,7 +33,7 @@ public void clear() {
}
@Nullable
- public PushNotificationProps get() {
+ public NotificationProps get() {
return mNotification;
}
}
diff --git a/android/src/main/java/com/wix/reactnativenotifications/core/JsIOHelper.java b/android/src/main/java/com/wix/reactnativenotifications/core/JsIOHelper.java
index 4d8f4d1d5..ba49f96d0 100644
--- a/android/src/main/java/com/wix/reactnativenotifications/core/JsIOHelper.java
+++ b/android/src/main/java/com/wix/reactnativenotifications/core/JsIOHelper.java
@@ -1,26 +1,38 @@
package com.wix.reactnativenotifications.core;
+import android.content.Context;
import android.os.Bundle;
+import com.facebook.react.ReactApplication;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.modules.core.DeviceEventManagerModule;
public class JsIOHelper {
- public boolean sendEventToJS(String eventName, Bundle data, ReactContext reactContext) {
- if (reactContext != null) {
- sendEventToJS(eventName, Arguments.fromBundle(data), reactContext);
- return true;
- }
- return false;
+
+ private final Context mContext;
+
+ public JsIOHelper(Context context) {
+ mContext = context;
}
- public boolean sendEventToJS(String eventName, WritableMap data, ReactContext reactContext) {
- if (reactContext != null) {
- reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName, data);
+ public boolean sendEventToJS(String eventName, Bundle bundle) {
+ return sendEventToJS(eventName, Arguments.fromBundle(bundle));
+ }
+
+ public boolean sendEventToJS(String eventName, String string) {
+ return sendEventToJS(eventName, (Object) string);
+ }
+
+ boolean sendEventToJS(String eventName, Object object) {
+ final ReactContext reactContext = ((ReactApplication) mContext.getApplicationContext()).getReactNativeHost().getReactInstanceManager().getCurrentReactContext();
+
+ if (reactContext != null && reactContext.hasActiveCatalystInstance()) {
+ reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(eventName, object);
return true;
}
+
return false;
}
}
diff --git a/android/src/main/java/com/wix/reactnativenotifications/core/NotificationIntentAdapter.java b/android/src/main/java/com/wix/reactnativenotifications/core/NotificationIntentAdapter.java
index 0413e2f86..e00b92a95 100644
--- a/android/src/main/java/com/wix/reactnativenotifications/core/NotificationIntentAdapter.java
+++ b/android/src/main/java/com/wix/reactnativenotifications/core/NotificationIntentAdapter.java
@@ -5,13 +5,13 @@
import android.content.Intent;
import android.os.Bundle;
-import com.wix.reactnativenotifications.core.notification.PushNotificationProps;
+import com.wix.reactnativenotifications.core.notifications.NotificationProps;
public class NotificationIntentAdapter {
private static final int PENDING_INTENT_CODE = 0;
private static final String PUSH_NOTIFICATION_EXTRA_NAME = "pushNotification";
- public static PendingIntent createPendingNotificationIntent(Context appContext, Intent intent, PushNotificationProps notification) {
+ public static PendingIntent createPendingNotificationIntent(Context appContext, Intent intent, NotificationProps notification) {
intent.putExtra(PUSH_NOTIFICATION_EXTRA_NAME, notification.asBundle());
return PendingIntent.getService(appContext, PENDING_INTENT_CODE, intent, PendingIntent.FLAG_ONE_SHOT);
}
diff --git a/android/src/main/java/com/wix/reactnativenotifications/core/ProxyService.java b/android/src/main/java/com/wix/reactnativenotifications/core/ProxyService.java
index f1abbb2ce..3985c4dfb 100644
--- a/android/src/main/java/com/wix/reactnativenotifications/core/ProxyService.java
+++ b/android/src/main/java/com/wix/reactnativenotifications/core/ProxyService.java
@@ -5,8 +5,9 @@
import android.os.Bundle;
import android.util.Log;
-import com.wix.reactnativenotifications.core.notification.IPushNotification;
-import com.wix.reactnativenotifications.core.notification.PushNotification;
+import com.wix.reactnativenotifications.core.notifications.ILocalNotification;
+import com.wix.reactnativenotifications.core.notifications.LocalNotification;
+import com.wix.reactnativenotifications.core.notifications.NotificationProps;
public class ProxyService extends IntentService {
@@ -19,10 +20,12 @@ public ProxyService() {
@Override
protected void onHandleIntent(Intent intent) {
Log.d(TAG, "New intent: "+intent);
- final Bundle notificationData = NotificationIntentAdapter.extractPendingNotificationDataFromIntent(intent);
- final IPushNotification pushNotification = PushNotification.get(this, notificationData);
- if (pushNotification != null) {
- pushNotification.onOpened();
+ final Bundle notificationBundle = NotificationIntentAdapter.extractPendingNotificationDataFromIntent(intent);
+
+ if (notificationBundle != null) {
+ final NotificationProps notificationProps = NotificationProps.fromBundle(this, notificationBundle);
+ final ILocalNotification localNotification = LocalNotification.get(this, notificationProps);
+ localNotification.onOpened();
}
}
}
diff --git a/android/src/main/java/com/wix/reactnativenotifications/core/notification/INotificationsApplication.java b/android/src/main/java/com/wix/reactnativenotifications/core/notification/INotificationsApplication.java
deleted file mode 100644
index 25cf21b9f..000000000
--- a/android/src/main/java/com/wix/reactnativenotifications/core/notification/INotificationsApplication.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package com.wix.reactnativenotifications.core.notification;
-
-import android.content.Context;
-import android.os.Bundle;
-
-import com.wix.reactnativenotifications.core.AppLaunchHelper;
-import com.wix.reactnativenotifications.core.AppLifecycleFacade;
-
-public interface INotificationsApplication {
- IPushNotification getPushNotification(Context context, Bundle bundle, AppLifecycleFacade facade, AppLaunchHelper defaultAppLaunchHelper);
-}
diff --git a/android/src/main/java/com/wix/reactnativenotifications/core/notification/IPushNotification.java b/android/src/main/java/com/wix/reactnativenotifications/core/notification/IPushNotification.java
deleted file mode 100644
index 0d70024ac..000000000
--- a/android/src/main/java/com/wix/reactnativenotifications/core/notification/IPushNotification.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.wix.reactnativenotifications.core.notification;
-
-public interface IPushNotification {
- class InvalidNotificationException extends Exception {
- public InvalidNotificationException(String detailMessage) {
- super(detailMessage);
- }
- }
-
- /**
- * Handle an event where notification has just been received.
- * @throws InvalidNotificationException
- */
- void onReceived() throws InvalidNotificationException;
-
- /**
- * Handle an event where notification has already been dispatched and is not being opened by the device user.
- */
- void onOpened();
-
- /**
- * Handle a request to post this notification.
- *
- * @param notificationId (optional) The specific ID to associated with the notification.
- * @return The ID effectively assigned to the notification (Auto-assigned if not specified as a parameter).
- */
- int onPostRequest(Integer notificationId);
-
- PushNotificationProps asProps();
-}
diff --git a/android/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotificationProps.java b/android/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotificationProps.java
deleted file mode 100644
index b155dfa03..000000000
--- a/android/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotificationProps.java
+++ /dev/null
@@ -1,47 +0,0 @@
-package com.wix.reactnativenotifications.core.notification;
-
-import android.os.Bundle;
-
-public class PushNotificationProps {
-
- protected Bundle mBundle;
-
- public PushNotificationProps() {
- mBundle = new Bundle();
- }
-
- public PushNotificationProps(String title, String body) {
- mBundle = new Bundle();
- mBundle.putString("title", title);
- mBundle.putString("body", body);
- }
-
- public PushNotificationProps(Bundle bundle) {
- mBundle = bundle;
- }
-
- public String getTitle() {
- return mBundle.getString("title");
- }
-
- public String getBody() {
- return mBundle.getString("body");
- }
-
- public Bundle asBundle() {
- return (Bundle) mBundle.clone();
- }
-
- @Override
- public String toString() {
- StringBuilder sb = new StringBuilder(1024);
- for (String key : mBundle.keySet()) {
- sb.append(key).append("=").append(mBundle.get(key)).append(", ");
- }
- return sb.toString();
- }
-
- protected PushNotificationProps copy() {
- return new PushNotificationProps((Bundle) mBundle.clone());
- }
-}
diff --git a/android/src/main/java/com/wix/reactnativenotifications/core/notificationdrawer/IPushNotificationsDrawer.java b/android/src/main/java/com/wix/reactnativenotifications/core/notificationdrawer/INotificationDrawer.java
similarity index 53%
rename from android/src/main/java/com/wix/reactnativenotifications/core/notificationdrawer/IPushNotificationsDrawer.java
rename to android/src/main/java/com/wix/reactnativenotifications/core/notificationdrawer/INotificationDrawer.java
index 3be3dc1e5..0df866489 100644
--- a/android/src/main/java/com/wix/reactnativenotifications/core/notificationdrawer/IPushNotificationsDrawer.java
+++ b/android/src/main/java/com/wix/reactnativenotifications/core/notificationdrawer/INotificationDrawer.java
@@ -1,12 +1,15 @@
package com.wix.reactnativenotifications.core.notificationdrawer;
import android.app.Activity;
+import android.support.annotation.Nullable;
-public interface IPushNotificationsDrawer {
+public interface INotificationDrawer {
void onAppInit();
void onAppVisible();
void onNewActivity(Activity activity);
void onNotificationOpened();
- void onNotificationClearRequest(int id);
+
+ void onCancelLocalNotification(@Nullable String tag, int id);
+ void onCancelAllLocalNotifications();
}
diff --git a/android/src/main/java/com/wix/reactnativenotifications/core/notificationdrawer/INotificationsDrawerApplication.java b/android/src/main/java/com/wix/reactnativenotifications/core/notificationdrawer/INotificationDrawerApplication.java
similarity index 50%
rename from android/src/main/java/com/wix/reactnativenotifications/core/notificationdrawer/INotificationsDrawerApplication.java
rename to android/src/main/java/com/wix/reactnativenotifications/core/notificationdrawer/INotificationDrawerApplication.java
index 77d83d60e..2007a3727 100644
--- a/android/src/main/java/com/wix/reactnativenotifications/core/notificationdrawer/INotificationsDrawerApplication.java
+++ b/android/src/main/java/com/wix/reactnativenotifications/core/notificationdrawer/INotificationDrawerApplication.java
@@ -4,6 +4,6 @@
import com.wix.reactnativenotifications.core.AppLaunchHelper;
-public interface INotificationsDrawerApplication {
- IPushNotificationsDrawer getPushNotificationsDrawer(Context context, AppLaunchHelper defaultAppLaunchHelper);
+public interface INotificationDrawerApplication {
+ INotificationDrawer getNotificationsDrawer(Context context, AppLaunchHelper defaultAppLaunchHelper);
}
diff --git a/android/src/main/java/com/wix/reactnativenotifications/core/notificationdrawer/PushNotificationsDrawer.java b/android/src/main/java/com/wix/reactnativenotifications/core/notificationdrawer/NotificationDrawer.java
similarity index 58%
rename from android/src/main/java/com/wix/reactnativenotifications/core/notificationdrawer/PushNotificationsDrawer.java
rename to android/src/main/java/com/wix/reactnativenotifications/core/notificationdrawer/NotificationDrawer.java
index 7b320e16d..bb4e26070 100644
--- a/android/src/main/java/com/wix/reactnativenotifications/core/notificationdrawer/PushNotificationsDrawer.java
+++ b/android/src/main/java/com/wix/reactnativenotifications/core/notificationdrawer/NotificationDrawer.java
@@ -3,29 +3,32 @@
import android.app.Activity;
import android.app.NotificationManager;
import android.content.Context;
+import android.content.Intent;
+import android.support.annotation.Nullable;
import com.wix.reactnativenotifications.core.AppLaunchHelper;
import com.wix.reactnativenotifications.core.InitialNotificationHolder;
+import com.wix.reactnativenotifications.core.notifications.NotificationProps;
-public class PushNotificationsDrawer implements IPushNotificationsDrawer {
+public class NotificationDrawer implements INotificationDrawer {
- final protected Context mContext;
- final protected AppLaunchHelper mAppLaunchHelper;
+ protected final Context mContext;
+ protected final AppLaunchHelper mAppLaunchHelper;
- public static IPushNotificationsDrawer get(Context context) {
- return PushNotificationsDrawer.get(context, new AppLaunchHelper());
+ public static INotificationDrawer get(Context context) {
+ return NotificationDrawer.get(context, new AppLaunchHelper());
}
- public static IPushNotificationsDrawer get(Context context, AppLaunchHelper appLaunchHelper) {
+ public static INotificationDrawer get(Context context, AppLaunchHelper appLaunchHelper) {
final Context appContext = context.getApplicationContext();
- if (appContext instanceof INotificationsDrawerApplication) {
- return ((INotificationsDrawerApplication) appContext).getPushNotificationsDrawer(context, appLaunchHelper);
+ if (appContext instanceof INotificationDrawerApplication) {
+ return ((INotificationDrawerApplication) appContext).getNotificationsDrawer(context, appLaunchHelper);
}
- return new PushNotificationsDrawer(context, appLaunchHelper);
+ return new NotificationDrawer(context, appLaunchHelper);
}
- protected PushNotificationsDrawer(Context context, AppLaunchHelper appLaunchHelper) {
+ protected NotificationDrawer(Context context, AppLaunchHelper appLaunchHelper) {
mContext = context;
mAppLaunchHelper = appLaunchHelper;
}
@@ -55,9 +58,14 @@ public void onNotificationOpened() {
}
@Override
- public void onNotificationClearRequest(int id) {
+ public void onCancelLocalNotification(@Nullable String tag, int id) {
final NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
- notificationManager.cancel(id);
+ notificationManager.cancel(tag, id);
+ }
+
+ @Override
+ public void onCancelAllLocalNotifications() {
+ clearAll();
}
protected void clearAll() {
diff --git a/android/src/main/java/com/wix/reactnativenotifications/core/notifications/ILocalNotification.java b/android/src/main/java/com/wix/reactnativenotifications/core/notifications/ILocalNotification.java
new file mode 100644
index 000000000..a8013ccfa
--- /dev/null
+++ b/android/src/main/java/com/wix/reactnativenotifications/core/notifications/ILocalNotification.java
@@ -0,0 +1,19 @@
+package com.wix.reactnativenotifications.core.notifications;
+
+import android.support.annotation.Nullable;
+
+public interface ILocalNotification {
+
+ /**
+ * Post this notification.
+ *
+ * @param notificationId (optional) The specific ID to associated with the notification.
+ * @return The ID effectively assigned to the notification (Auto-assigned if not specified as a parameter).
+ */
+ int post(@Nullable Integer notificationId);
+
+ /**
+ * Handle an event where notification has already been dispatched and is not being opened by the device user.
+ */
+ void onOpened();
+}
diff --git a/android/src/main/java/com/wix/reactnativenotifications/core/notifications/INotificationsApplication.java b/android/src/main/java/com/wix/reactnativenotifications/core/notifications/INotificationsApplication.java
new file mode 100644
index 000000000..78d0817d7
--- /dev/null
+++ b/android/src/main/java/com/wix/reactnativenotifications/core/notifications/INotificationsApplication.java
@@ -0,0 +1,10 @@
+package com.wix.reactnativenotifications.core.notifications;
+
+import android.content.Context;
+
+import com.wix.reactnativenotifications.core.AppLaunchHelper;
+import com.wix.reactnativenotifications.core.AppLifecycleFacade;
+
+public interface INotificationsApplication {
+ ILocalNotification getLocalNotification(Context context, NotificationProps notificationProps, AppLifecycleFacade facade, AppLaunchHelper defaultAppLaunchHelper);
+}
diff --git a/android/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java b/android/src/main/java/com/wix/reactnativenotifications/core/notifications/LocalNotification.java
similarity index 57%
rename from android/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java
rename to android/src/main/java/com/wix/reactnativenotifications/core/notifications/LocalNotification.java
index 9fec1de6b..cea627ea9 100644
--- a/android/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java
+++ b/android/src/main/java/com/wix/reactnativenotifications/core/notifications/LocalNotification.java
@@ -1,11 +1,15 @@
-package com.wix.reactnativenotifications.core.notification;
+package com.wix.reactnativenotifications.core.notifications;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
-import android.os.Bundle;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.net.Uri;
+import android.os.Build;
+import android.util.Log;
import com.facebook.react.bridge.ReactContext;
import com.wix.reactnativenotifications.core.AppLaunchHelper;
@@ -17,17 +21,18 @@
import com.wix.reactnativenotifications.core.NotificationIntentAdapter;
import com.wix.reactnativenotifications.core.ProxyService;
+import static com.wix.reactnativenotifications.Defs.LOGTAG;
import static com.wix.reactnativenotifications.Defs.NOTIFICATION_OPENED_EVENT_NAME;
-import static com.wix.reactnativenotifications.Defs.NOTIFICATION_RECEIVED_EVENT_NAME;
-public class PushNotification implements IPushNotification {
+public class LocalNotification implements ILocalNotification {
+
+ private final Context mContext;
+ private final NotificationProps mNotificationProps;
+ private final AppLifecycleFacade mAppLifecycleFacade;
+ private final AppLaunchHelper mAppLaunchHelper;
+ private final JsIOHelper mJsIOHelper;
+ private final AppVisibilityListener mAppVisibilityListener = new AppVisibilityListener() {
- final protected Context mContext;
- final protected AppLifecycleFacade mAppLifecycleFacade;
- final protected AppLaunchHelper mAppLaunchHelper;
- final protected JsIOHelper mJsIOHelper;
- final protected PushNotificationProps mNotificationProps;
- final protected AppVisibilityListener mAppVisibilityListener = new AppVisibilityListener() {
@Override
public void onAppVisible() {
mAppLifecycleFacade.removeVisibilityListener(this);
@@ -39,26 +44,36 @@ public void onAppNotVisible() {
}
};
- public static IPushNotification get(Context context, Bundle bundle) {
- Context appContext = context.getApplicationContext();
+ public static ILocalNotification get(Context context, NotificationProps localNotificationProps) {
+ final AppLifecycleFacade appLifecycleFacade = AppLifecycleFacadeHolder.get();
+ final AppLaunchHelper appLaunchHelper = new AppLaunchHelper();
+ final Context appContext = context.getApplicationContext();
+
if (appContext instanceof INotificationsApplication) {
- return ((INotificationsApplication) appContext).getPushNotification(context, bundle, AppLifecycleFacadeHolder.get(), new AppLaunchHelper());
+ return ((INotificationsApplication) appContext).getLocalNotification(context, localNotificationProps, AppLifecycleFacadeHolder.get(), new AppLaunchHelper());
}
- return new PushNotification(context, bundle, AppLifecycleFacadeHolder.get(), new AppLaunchHelper(), new JsIOHelper());
+
+ return new LocalNotification(context, localNotificationProps, appLifecycleFacade, appLaunchHelper);
}
- protected PushNotification(Context context, Bundle bundle, AppLifecycleFacade appLifecycleFacade, AppLaunchHelper appLaunchHelper, JsIOHelper JsIOHelper) {
+ protected LocalNotification(Context context, NotificationProps localNotificationProps, AppLifecycleFacade appLifecycleFacade, AppLaunchHelper appLaunchHelper, JsIOHelper jsIOHelper) {
mContext = context;
+ mNotificationProps = localNotificationProps;
mAppLifecycleFacade = appLifecycleFacade;
mAppLaunchHelper = appLaunchHelper;
- mJsIOHelper = JsIOHelper;
- mNotificationProps = createProps(bundle);
+ mJsIOHelper = jsIOHelper;
+ }
+
+ protected LocalNotification(Context context, NotificationProps localNotificationProps, AppLifecycleFacade appLifecycleFacade, AppLaunchHelper appLaunchHelper) {
+ this(context, localNotificationProps, appLifecycleFacade, appLaunchHelper, new JsIOHelper(context));
}
@Override
- public void onReceived() throws InvalidNotificationException {
- postNotification(null);
- notifyReceivedToJS();
+ public int post(Integer notificationId) {
+ final PendingIntent pendingIntent = getCTAPendingIntent();
+ final int id = notificationId != null ? notificationId : createNotificationId();
+ postNotification(id, getNotificationBuilder(pendingIntent).build());
+ return id;
}
@Override
@@ -67,22 +82,6 @@ public void onOpened() {
clearAllNotifications();
}
- @Override
- public int onPostRequest(Integer notificationId) {
- return postNotification(notificationId);
- }
-
- @Override
- public PushNotificationProps asProps() {
- return mNotificationProps.copy();
- }
-
- protected int postNotification(Integer notificationId) {
- final PendingIntent pendingIntent = getCTAPendingIntent();
- final Notification notification = buildNotification(pendingIntent);
- return postNotification(notification, notificationId);
- }
-
protected void digestNotification() {
if (!mAppLifecycleFacade.isReactInitialized()) {
setAsInitialNotification();
@@ -102,16 +101,12 @@ protected void digestNotification() {
}
}
- protected PushNotificationProps createProps(Bundle bundle) {
- return new PushNotificationProps(bundle);
- }
-
protected void setAsInitialNotification() {
InitialNotificationHolder.getInstance().set(mNotificationProps);
}
protected void dispatchImmediately() {
- notifyOpenedToJS();
+ sendOpenedEvent();
}
protected void dispatchUponVisibility() {
@@ -131,29 +126,29 @@ protected PendingIntent getCTAPendingIntent() {
return NotificationIntentAdapter.createPendingNotificationIntent(mContext, cta, mNotificationProps);
}
- protected Notification buildNotification(PendingIntent intent) {
- return getNotificationBuilder(intent).build();
- }
-
protected Notification.Builder getNotificationBuilder(PendingIntent intent) {
- return new Notification.Builder(mContext)
+ final Integer icon = mNotificationProps.getIcon();
+ final Integer color = mNotificationProps.getColor();
+
+ final Notification.Builder builder = new Notification.Builder(mContext)
.setContentTitle(mNotificationProps.getTitle())
.setContentText(mNotificationProps.getBody())
- .setSmallIcon(mContext.getApplicationInfo().icon)
+ .setSmallIcon(icon != null ? icon : mContext.getApplicationContext().getApplicationInfo().icon)
+ .setSound(mNotificationProps.getSound())
.setContentIntent(intent)
.setDefaults(Notification.DEFAULT_ALL)
.setAutoCancel(true);
- }
- protected int postNotification(Notification notification, Integer notificationId) {
- int id = notificationId != null ? notificationId : createNotificationId(notification);
- postNotification(id, notification);
- return id;
+ if (color != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ builder.setColor(color);
+ }
+
+ return builder;
}
protected void postNotification(int id, Notification notification) {
final NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
- notificationManager.notify(id, notification);
+ notificationManager.notify(mNotificationProps.getTag(), id, notification);
}
protected void clearAllNotifications() {
@@ -161,20 +156,16 @@ protected void clearAllNotifications() {
notificationManager.cancelAll();
}
- protected int createNotificationId(Notification notification) {
- return (int) System.nanoTime();
- }
-
- private void notifyReceivedToJS() {
- mJsIOHelper.sendEventToJS(NOTIFICATION_RECEIVED_EVENT_NAME, mNotificationProps.asBundle(), mAppLifecycleFacade.getRunningReactContext());
- }
-
- private void notifyOpenedToJS() {
- mJsIOHelper.sendEventToJS(NOTIFICATION_OPENED_EVENT_NAME, mNotificationProps.asBundle(), mAppLifecycleFacade.getRunningReactContext());
+ protected int createNotificationId() {
+ return mNotificationProps.getTag() != null ? 0 : (int) System.nanoTime();
}
protected void launchOrResumeApp() {
final Intent intent = mAppLaunchHelper.getLaunchIntent(mContext);
mContext.startActivity(intent);
}
+
+ private void sendOpenedEvent() {
+ mJsIOHelper.sendEventToJS(NOTIFICATION_OPENED_EVENT_NAME, mNotificationProps.asBundle());
+ }
}
diff --git a/android/src/main/java/com/wix/reactnativenotifications/core/notifications/NotificationProps.java b/android/src/main/java/com/wix/reactnativenotifications/core/notifications/NotificationProps.java
new file mode 100644
index 000000000..5361a6af6
--- /dev/null
+++ b/android/src/main/java/com/wix/reactnativenotifications/core/notifications/NotificationProps.java
@@ -0,0 +1,146 @@
+package com.wix.reactnativenotifications.core.notifications;
+
+import android.content.Context;
+import android.graphics.Color;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+
+import com.google.firebase.messaging.RemoteMessage;
+
+import java.util.Map;
+
+public class NotificationProps {
+
+ // Local & remote (Firebase) support
+
+ private static final String TITLE = "title";
+ private static final String BODY = "body";
+ private static final String ICON = "icon";
+ private static final String SOUND = "sound";
+ private static final String TAG = "tag";
+ private static final String COLOR = "color";
+
+ private static final String DATA = "data";
+
+ // Local-only support
+
+ public static NotificationProps fromRemoteMessage(Context context, RemoteMessage remoteMessage) {
+ final Bundle properties = new Bundle();
+ final RemoteMessage.Notification notification = remoteMessage.getNotification();
+
+ if (notification != null) {
+ properties.putString(TITLE, notification.getTitle());
+ properties.putString(BODY, notification.getBody());
+ properties.putString(ICON, notification.getIcon());
+ properties.putString(SOUND, notification.getSound());
+ properties.putString(TAG, notification.getTag());
+ properties.putString(COLOR, notification.getColor());
+ }
+
+ final Map data = remoteMessage.getData();
+
+ if (data != null) {
+ final Bundle dataBundle = new Bundle();
+
+ for (final Map.Entry entry : data.entrySet()) {
+ dataBundle.putString(entry.getKey(), entry.getValue());
+ }
+
+ properties.putBundle(DATA, dataBundle);
+ }
+
+ return new NotificationProps(context, properties);
+ }
+
+ public static NotificationProps fromBundle(Context context, Bundle bundle) {
+ return new NotificationProps(context, new Bundle(bundle));
+ }
+
+ private Context mContext;
+ private Bundle mProperties;
+
+ protected NotificationProps(Context context, Bundle properties) {
+ mContext = context;
+ mProperties = properties;
+ }
+
+ @Nullable
+ public String getTitle() {
+ return mProperties.getString(TITLE);
+ }
+
+ @Nullable
+ public String getBody() {
+ return mProperties.getString(BODY);
+ }
+
+ @Nullable
+ public Integer getIcon() {
+ return drawableIdFromString(mProperties.getString(ICON));
+ }
+
+ @Nullable
+ public Uri getSound() {
+ return rawResourceUriFromString(mProperties.getString(SOUND));
+ }
+
+ @Nullable
+ public String getTag() {
+ return mProperties.getString(TAG);
+ }
+
+ @Nullable
+ public Integer getColor() {
+ return colorFromString(mProperties.getString(COLOR));
+ }
+
+ @Nullable
+ public Bundle getData() {
+ return mProperties.getBundle(DATA);
+ }
+
+ public Bundle asBundle() {
+ return new Bundle(mProperties);
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder(1024);
+ for (String key : mProperties.keySet()) {
+ sb.append(key).append("=").append(mProperties.get(key)).append(", ");
+ }
+ return sb.toString();
+ }
+
+ @Nullable
+ private Integer colorFromString(String string) {
+ if (string != null) {
+ try {
+ return Color.parseColor(string);
+ } catch (IllegalArgumentException e) {
+ // Move on
+ }
+ }
+
+ return null;
+ }
+
+ @Nullable
+ private Integer drawableIdFromString(String string) {
+ if (string != null) {
+ int id = mContext.getResources().getIdentifier(string, "drawable", mContext.getPackageName());
+
+ if (id != 0) {
+ return id;
+ }
+ }
+
+ return null;
+ }
+
+ @Nullable
+ private Uri rawResourceUriFromString(String string) {
+ return string != null ? Uri.parse("android.resource://" + mContext.getPackageName() + "/raw/" + string) : null;
+ }
+}
diff --git a/android/src/main/java/com/wix/reactnativenotifications/core/notifications/RemoteNotification.java b/android/src/main/java/com/wix/reactnativenotifications/core/notifications/RemoteNotification.java
new file mode 100644
index 000000000..75d780324
--- /dev/null
+++ b/android/src/main/java/com/wix/reactnativenotifications/core/notifications/RemoteNotification.java
@@ -0,0 +1,30 @@
+package com.wix.reactnativenotifications.core.notifications;
+
+import android.content.Context;
+
+import com.wix.reactnativenotifications.core.JsIOHelper;
+
+import static com.wix.reactnativenotifications.Defs.NOTIFICATION_RECEIVED_EVENT_NAME;
+
+public class RemoteNotification {
+
+ private final NotificationProps mNotificationProps;
+ private final JsIOHelper mJsIOHelper;
+
+ protected RemoteNotification(NotificationProps notificationProps, JsIOHelper jsIOHelper) {
+ mNotificationProps = notificationProps;
+ mJsIOHelper = jsIOHelper;
+ }
+
+ public RemoteNotification(Context context, NotificationProps notificationProps) {
+ this(notificationProps, new JsIOHelper(context));
+ }
+
+ public void onReceived() {
+ sendReceivedEvent();
+ }
+
+ private void sendReceivedEvent() {
+ mJsIOHelper.sendEventToJS(NOTIFICATION_RECEIVED_EVENT_NAME, mNotificationProps.asBundle());
+ }
+}
diff --git a/android/src/main/java/com/wix/reactnativenotifications/fcm/FcmInstanceIdListenerService.java b/android/src/main/java/com/wix/reactnativenotifications/fcm/FcmInstanceIdListenerService.java
new file mode 100644
index 000000000..df158ab0a
--- /dev/null
+++ b/android/src/main/java/com/wix/reactnativenotifications/fcm/FcmInstanceIdListenerService.java
@@ -0,0 +1,15 @@
+package com.wix.reactnativenotifications.fcm;
+
+import android.content.Intent;
+
+import com.google.firebase.iid.FirebaseInstanceIdService;
+
+public class FcmInstanceIdListenerService extends FirebaseInstanceIdService {
+
+ @Override
+ public void onTokenRefresh() {
+ final Intent intent = new Intent(this, FcmTokenService.class);
+ intent.setAction(FcmTokenService.ACTION_REFRESH_TOKEN);
+ startService(intent);
+ }
+}
diff --git a/android/src/main/java/com/wix/reactnativenotifications/fcm/FcmMessageHandlerService.java b/android/src/main/java/com/wix/reactnativenotifications/fcm/FcmMessageHandlerService.java
new file mode 100644
index 000000000..90151bfea
--- /dev/null
+++ b/android/src/main/java/com/wix/reactnativenotifications/fcm/FcmMessageHandlerService.java
@@ -0,0 +1,20 @@
+package com.wix.reactnativenotifications.fcm;
+
+import android.util.Log;
+
+import com.google.firebase.messaging.FirebaseMessagingService;
+import com.google.firebase.messaging.RemoteMessage;
+import com.wix.reactnativenotifications.core.notifications.NotificationProps;
+import com.wix.reactnativenotifications.core.notifications.RemoteNotification;
+
+import static com.wix.reactnativenotifications.Defs.LOGTAG;
+
+public class FcmMessageHandlerService extends FirebaseMessagingService {
+
+ @Override
+ public void onMessageReceived(RemoteMessage message) {
+ Log.d(LOGTAG, "New message from firebase");
+ final NotificationProps notificationProps = NotificationProps.fromRemoteMessage(this, message);
+ new RemoteNotification(this, notificationProps).onReceived();
+ }
+}
diff --git a/android/src/main/java/com/wix/reactnativenotifications/fcm/FcmTokenBridge.java b/android/src/main/java/com/wix/reactnativenotifications/fcm/FcmTokenBridge.java
new file mode 100644
index 000000000..17c959c2e
--- /dev/null
+++ b/android/src/main/java/com/wix/reactnativenotifications/fcm/FcmTokenBridge.java
@@ -0,0 +1,39 @@
+package com.wix.reactnativenotifications.fcm;
+
+import android.content.Context;
+import android.util.Log;
+
+import com.google.firebase.iid.FirebaseInstanceId;
+import com.wix.reactnativenotifications.core.JsIOHelper;
+
+import static com.wix.reactnativenotifications.Defs.LOGTAG;
+import static com.wix.reactnativenotifications.Defs.TOKEN_RECEIVED_EVENT_NAME;
+
+public class FcmTokenBridge {
+
+ private final FirebaseInstanceId mFirebaseInstanceId;
+ private final JsIOHelper mJsIOHelper;
+
+ protected FcmTokenBridge(FirebaseInstanceId firebaseInstanceId, JsIOHelper jsIOHelper) {
+ mFirebaseInstanceId = firebaseInstanceId;
+ mJsIOHelper = jsIOHelper;
+ }
+
+ public FcmTokenBridge(Context context) {
+ this(FirebaseInstanceId.getInstance(), new JsIOHelper(context));
+ }
+
+ public void refreshToken() {
+ try {
+ sendReceivedEvent();
+ } catch (Exception e) {
+ Log.e(LOGTAG, "Failed to refresh FCM token", e);
+ }
+ }
+
+ private void sendReceivedEvent() {
+ final String token = mFirebaseInstanceId.getToken();
+ Log.i(LOGTAG, "Firebase has a new token: FirebaseInstanceId=" + mFirebaseInstanceId.getId() + ", token=" + token);
+ mJsIOHelper.sendEventToJS(TOKEN_RECEIVED_EVENT_NAME, token);
+ }
+}
diff --git a/android/src/main/java/com/wix/reactnativenotifications/fcm/FcmTokenService.java b/android/src/main/java/com/wix/reactnativenotifications/fcm/FcmTokenService.java
new file mode 100644
index 000000000..e541dfb1d
--- /dev/null
+++ b/android/src/main/java/com/wix/reactnativenotifications/fcm/FcmTokenService.java
@@ -0,0 +1,26 @@
+package com.wix.reactnativenotifications.fcm;
+
+import android.app.IntentService;
+import android.content.Intent;
+
+public class FcmTokenService extends IntentService {
+
+ public static final String ACTION_REFRESH_TOKEN = "com.wix.reactnativenotifications.fcm.ACTION_REFRESH_TOKEN";
+
+ private FcmTokenBridge fcmTokenBridge;
+
+ public FcmTokenService() {
+ super(FcmTokenService.class.getSimpleName());
+
+ fcmTokenBridge = new FcmTokenBridge(this);
+ }
+
+ @Override
+ protected void onHandleIntent(Intent intent) {
+ final String action = intent.getAction();
+
+ if (ACTION_REFRESH_TOKEN.equals(action)) {
+ fcmTokenBridge.refreshToken();
+ }
+ }
+}
diff --git a/android/src/main/java/com/wix/reactnativenotifications/gcm/GcmInstanceIdListenerService.java b/android/src/main/java/com/wix/reactnativenotifications/gcm/GcmInstanceIdListenerService.java
deleted file mode 100644
index 933415f5c..000000000
--- a/android/src/main/java/com/wix/reactnativenotifications/gcm/GcmInstanceIdListenerService.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.wix.reactnativenotifications.gcm;
-
-import android.content.Intent;
-
-import com.google.android.gms.iid.InstanceIDListenerService;
-
-/**
- * Instance-ID + token refreshing handling service. Contacts the GCM to fetch the updated token.
- *
- * @author amitd
- */
-public class GcmInstanceIdListenerService extends InstanceIDListenerService {
-
- @Override
- public void onTokenRefresh() {
- // Fetch updated Instance ID token and notify our app's server of any changes (if applicable).
- // Google recommends running this from an intent service.
- Intent intent = new Intent(this, GcmInstanceIdRefreshHandlerService.class);
- startService(intent);
- }
-}
diff --git a/android/src/main/java/com/wix/reactnativenotifications/gcm/GcmInstanceIdRefreshHandlerService.java b/android/src/main/java/com/wix/reactnativenotifications/gcm/GcmInstanceIdRefreshHandlerService.java
deleted file mode 100644
index 3aa7aa9dc..000000000
--- a/android/src/main/java/com/wix/reactnativenotifications/gcm/GcmInstanceIdRefreshHandlerService.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package com.wix.reactnativenotifications.gcm;
-
-import android.app.IntentService;
-import android.content.Intent;
-
-public class GcmInstanceIdRefreshHandlerService extends IntentService {
-
- public static String EXTRA_IS_APP_INIT = "isAppInit";
- public static String EXTRA_MANUAL_REFRESH = "doManualRefresh";
-
- public GcmInstanceIdRefreshHandlerService() {
- super(GcmInstanceIdRefreshHandlerService.class.getSimpleName());
- }
-
- @Override
- protected void onHandleIntent(Intent intent) {
- IGcmToken gcmToken = GcmToken.get(this);
- if (gcmToken == null) {
- return;
- }
-
- if (intent.getBooleanExtra(EXTRA_IS_APP_INIT, false)) {
- gcmToken.onAppReady();
- } else if (intent.getBooleanExtra(EXTRA_MANUAL_REFRESH, false)) {
- gcmToken.onManualRefresh();
- } else {
- gcmToken.onNewTokenReady();
- }
- }
-}
diff --git a/android/src/main/java/com/wix/reactnativenotifications/gcm/GcmMessageHandlerService.java b/android/src/main/java/com/wix/reactnativenotifications/gcm/GcmMessageHandlerService.java
deleted file mode 100644
index f59665529..000000000
--- a/android/src/main/java/com/wix/reactnativenotifications/gcm/GcmMessageHandlerService.java
+++ /dev/null
@@ -1,26 +0,0 @@
-package com.wix.reactnativenotifications.gcm;
-
-import android.os.Bundle;
-import android.util.Log;
-
-import com.google.android.gms.gcm.GcmListenerService;
-import com.wix.reactnativenotifications.core.notification.IPushNotification;
-import com.wix.reactnativenotifications.core.notification.PushNotification;
-
-import static com.wix.reactnativenotifications.Defs.LOGTAG;
-
-public class GcmMessageHandlerService extends GcmListenerService {
-
- @Override
- public void onMessageReceived(String s, Bundle bundle) {
- Log.d(LOGTAG, "New message from GCM: " + bundle);
-
- try {
- final IPushNotification notification = PushNotification.get(getApplicationContext(), bundle);
- notification.onReceived();
- } catch (IPushNotification.InvalidNotificationException e) {
- // A GCM message, yes - but not the kind we know how to work with.
- Log.v(LOGTAG, "GCM message handling aborted", e);
- }
- }
-}
diff --git a/android/src/main/java/com/wix/reactnativenotifications/gcm/GcmToken.java b/android/src/main/java/com/wix/reactnativenotifications/gcm/GcmToken.java
deleted file mode 100644
index b11a6b5f4..000000000
--- a/android/src/main/java/com/wix/reactnativenotifications/gcm/GcmToken.java
+++ /dev/null
@@ -1,132 +0,0 @@
-package com.wix.reactnativenotifications.gcm;
-
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.support.annotation.NonNull;
-import android.util.Log;
-
-import com.facebook.react.ReactApplication;
-import com.facebook.react.ReactInstanceManager;
-import com.facebook.react.bridge.ReactContext;
-import com.facebook.react.modules.core.DeviceEventManagerModule;
-import com.google.android.gms.gcm.GoogleCloudMessaging;
-import com.google.android.gms.iid.InstanceID;
-
-import static com.wix.reactnativenotifications.Defs.GCM_SENDER_ID_ATTR_NAME;
-import static com.wix.reactnativenotifications.Defs.LOGTAG;
-import static com.wix.reactnativenotifications.Defs.TOKEN_RECEIVED_EVENT_NAME;
-
-public class GcmToken implements IGcmToken {
-
- final protected Context mAppContext;
-
- protected static String sToken;
-
- protected GcmToken(Context appContext) {
- if (!(appContext instanceof ReactApplication)) {
- throw new IllegalStateException("Application instance isn't a react-application");
- }
- mAppContext = appContext;
- }
-
- public static IGcmToken get(Context context) {
- Context appContext = context.getApplicationContext();
- if (appContext instanceof INotificationsGcmApplication) {
- return ((INotificationsGcmApplication) appContext).getGcmToken(context);
- }
- return new GcmToken(appContext);
- }
-
- @Override
- public void onNewTokenReady() {
- synchronized (mAppContext) {
- refreshToken();
- }
- }
-
- @Override
- public void onManualRefresh() {
- synchronized (mAppContext) {
- if (sToken == null) {
- Log.i(LOGTAG, "Manual token refresh => asking for new token");
- refreshToken();
- } else {
- Log.i(LOGTAG, "Manual token refresh => publishing existing token ("+sToken+")");
- sendTokenToJS();
- }
- }
- }
-
- @Override
- public void onAppReady() {
- synchronized (mAppContext) {
- if (sToken == null) {
- Log.i(LOGTAG, "App initialized => asking for new token");
- refreshToken();
- } else {
- // Except for first run, this should be the case.
- Log.i(LOGTAG, "App initialized => publishing existing token ("+sToken+")");
- sendTokenToJS();
- }
- }
- }
-
- protected void refreshToken() {
- try {
- sToken = getNewToken();
- } catch (Exception e) {
- Log.e(LOGTAG, "Failed to retrieve new token", e);
- return;
- }
-
- sendTokenToJS();
- }
-
- @NonNull
- protected String getNewToken() throws Exception {
- final InstanceID instanceId = InstanceID.getInstance(mAppContext);
- Log.d(LOGTAG, "GCM is refreshing token... instanceId=" + instanceId.getId());
-
- // TODO why is this needed?
- GoogleCloudMessaging.getInstance(mAppContext).close();
-
- try {
- final String registrationToken = instanceId.getToken(getSenderId(), GoogleCloudMessaging.INSTANCE_ID_SCOPE);
- Log.i(LOGTAG, "GCM has a new token: instanceId=" + instanceId.getId() + ", token=" + registrationToken);
- return registrationToken;
- } catch (Exception e) {
- throw new Exception("FATAL: Failed to fetch a fresh new token, instanceId=" + instanceId.getId(), e);
- }
- }
-
- protected String getSenderId() {
- final String senderId = getSenderIdFromManifest();
- if (senderId == null) {
- throw new IllegalStateException("Sender ID not found in manifest. Did you forget to add it as the value of a '"+GCM_SENDER_ID_ATTR_NAME+"' meta-data field?");
- }
- return senderId;
- }
-
- protected String getSenderIdFromManifest() {
- final ApplicationInfo appInfo;
- try {
- appInfo = mAppContext.getPackageManager().getApplicationInfo(mAppContext.getPackageName(), PackageManager.GET_META_DATA);
- return appInfo.metaData.getString(GCM_SENDER_ID_ATTR_NAME);
- } catch (PackageManager.NameNotFoundException e) {
- // Should REALLY never happen cause we're querying for our own package.
- Log.e(LOGTAG, "Failed to resolve sender ID from manifest", e);
- return null;
- }
- }
-
- protected void sendTokenToJS() {
- final ReactInstanceManager instanceManager = ((ReactApplication) mAppContext).getReactNativeHost().getReactInstanceManager();
- final ReactContext reactContext = instanceManager.getCurrentReactContext();
-
- // Note: Cannot assume react-context exists cause this is an async dispatched service.
- if (reactContext != null && reactContext.hasActiveCatalystInstance()) {
- reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit(TOKEN_RECEIVED_EVENT_NAME, sToken);
- }
- }
-}
diff --git a/android/src/main/java/com/wix/reactnativenotifications/gcm/IGcmToken.java b/android/src/main/java/com/wix/reactnativenotifications/gcm/IGcmToken.java
deleted file mode 100644
index f324a591f..000000000
--- a/android/src/main/java/com/wix/reactnativenotifications/gcm/IGcmToken.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package com.wix.reactnativenotifications.gcm;
-
-public interface IGcmToken {
-
- /**
- * Handle an event where we've been notified of a that a fresh token is now available from Google.
- */
- void onNewTokenReady();
-
- /**
- * Handle an event where application is ready; typically used for sending token to JS.
- */
- void onAppReady();
-
- /**
- * Handle a request to actively refresh the token on demand.
- * This is in essence a workaround so as to allow apps to handle end-cases of token refreshing. It
- * shouldn't be used by standard apps, as the token management is self sufficient.
- */
- void onManualRefresh();
-}
diff --git a/android/src/main/java/com/wix/reactnativenotifications/gcm/INotificationsGcmApplication.java b/android/src/main/java/com/wix/reactnativenotifications/gcm/INotificationsGcmApplication.java
deleted file mode 100644
index 36f59f71c..000000000
--- a/android/src/main/java/com/wix/reactnativenotifications/gcm/INotificationsGcmApplication.java
+++ /dev/null
@@ -1,7 +0,0 @@
-package com.wix.reactnativenotifications.gcm;
-
-import android.content.Context;
-
-public interface INotificationsGcmApplication {
- IGcmToken getGcmToken(Context context);
-}
diff --git a/android/src/test/java/com/wix/reactnativenotifications/core/InitialNotificationHolderTest.java b/android/src/test/java/com/wix/reactnativenotifications/core/InitialNotificationHolderTest.java
index 23fb7499a..56d6b281b 100644
--- a/android/src/test/java/com/wix/reactnativenotifications/core/InitialNotificationHolderTest.java
+++ b/android/src/test/java/com/wix/reactnativenotifications/core/InitialNotificationHolderTest.java
@@ -1,6 +1,6 @@
package com.wix.reactnativenotifications.core;
-import com.wix.reactnativenotifications.core.notification.PushNotificationProps;
+import com.wix.reactnativenotifications.core.notifications.NotificationProps;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -20,7 +20,7 @@ public void initialState() throws Exception {
@Test
public void setsInitialNotification() throws Exception {
- PushNotificationProps props = mock(PushNotificationProps.class);
+ NotificationProps props = mock(NotificationProps.class);
final InitialNotificationHolder uut = createUUT();
uut.set(props);
assertEquals(props, uut.get());
@@ -28,7 +28,7 @@ public void setsInitialNotification() throws Exception {
@Test
public void clearsInitialNotification() throws Exception {
- PushNotificationProps props = mock(PushNotificationProps.class);
+ NotificationProps props = mock(NotificationProps.class);
final InitialNotificationHolder uut = createUUT();
uut.set(props);
uut.clear();
@@ -37,8 +37,8 @@ public void clearsInitialNotification() throws Exception {
@Test
public void replacesInitialNotification() throws Exception {
- PushNotificationProps props1 = mock(PushNotificationProps.class);
- PushNotificationProps props2 = mock(PushNotificationProps.class);
+ NotificationProps props1 = mock(NotificationProps.class);
+ NotificationProps props2 = mock(NotificationProps.class);
final InitialNotificationHolder uut = createUUT();
uut.set(props1);
uut.set(props2);
@@ -56,4 +56,4 @@ public void isALazySingleton() throws Exception {
private InitialNotificationHolder createUUT() {
return new InitialNotificationHolder();
}
-}
\ No newline at end of file
+}
diff --git a/android/src/test/java/com/wix/reactnativenotifications/core/notificationdrawer/PushNotificationsDrawerTest.java b/android/src/test/java/com/wix/reactnativenotifications/core/notificationdrawer/NotificationsDrawerTest.java
similarity index 91%
rename from android/src/test/java/com/wix/reactnativenotifications/core/notificationdrawer/PushNotificationsDrawerTest.java
rename to android/src/test/java/com/wix/reactnativenotifications/core/notificationdrawer/NotificationsDrawerTest.java
index d65b0d763..637173cfa 100644
--- a/android/src/test/java/com/wix/reactnativenotifications/core/notificationdrawer/PushNotificationsDrawerTest.java
+++ b/android/src/test/java/com/wix/reactnativenotifications/core/notificationdrawer/NotificationsDrawerTest.java
@@ -18,13 +18,14 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@RunWith(RobolectricTestRunner.class)
-public class PushNotificationsDrawerTest {
+public class NotificationsDrawerTest {
@Mock private ReactContext mReactContext;
@Mock private Context mContext;
@@ -53,8 +54,8 @@ public void onAppVisible_clearAllNotifications() throws Exception {
@Test
public void onNotificationClearRequest_clearSpecificNotification() throws Exception {
- createUUT().onNotificationClearRequest(666);
- verify(mNotificationManager).cancel(eq(666));
+ createUUT().onCancelLocalNotification(null, 666);
+ verify(mNotificationManager).cancel((String) isNull(), eq(666));
verify(mNotificationManager, never()).cancelAll();
}
@@ -99,7 +100,7 @@ public void onNewActivity_activityLaunchedFromPushNotification_dontClearInitialN
verify(InitialNotificationHolder.getInstance(), never()).clear();
}
- protected PushNotificationsDrawer createUUT() {
- return new PushNotificationsDrawer(mContext, mAppLaunchHelper);
+ protected NotificationDrawer createUUT() {
+ return new NotificationDrawer(mContext, mAppLaunchHelper);
}
}
diff --git a/android/src/test/java/com/wix/reactnativenotifications/core/notification/PushNotificationTest.java b/android/src/test/java/com/wix/reactnativenotifications/core/notifications/LocalNotificationTest.java
similarity index 71%
rename from android/src/test/java/com/wix/reactnativenotifications/core/notification/PushNotificationTest.java
rename to android/src/test/java/com/wix/reactnativenotifications/core/notifications/LocalNotificationTest.java
index 5da598626..86d80c1c5 100644
--- a/android/src/test/java/com/wix/reactnativenotifications/core/notification/PushNotificationTest.java
+++ b/android/src/test/java/com/wix/reactnativenotifications/core/notifications/LocalNotificationTest.java
@@ -1,4 +1,4 @@
-package com.wix.reactnativenotifications.core.notification;
+package com.wix.reactnativenotifications.core.notifications;
import android.app.Activity;
import android.app.Notification;
@@ -25,6 +25,8 @@
import org.robolectric.Shadows;
import org.robolectric.shadows.ShadowNotification;
+import static com.wix.reactnativenotifications.Defs.NOTIFICATION_OPENED_EVENT_NAME;
+import static com.wix.reactnativenotifications.Defs.NOTIFICATION_RECEIVED_EVENT_NAME;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.mockito.ArgumentMatchers.any;
@@ -37,10 +39,7 @@
import static org.mockito.Mockito.when;
@RunWith(RobolectricTestRunner.class)
-public class PushNotificationTest {
-
- private static final String NOTIFICATION_OPENED_EVENT_NAME = "notificationOpened";
- private static final String NOTIFICATION_RECEIVED_EVENT_NAME = "notificationReceived";
+public class LocalNotificationTest {
private static final String DEFAULT_NOTIFICATION_TITLE = "Notification-title";
private static final String DEFAULT_NOTIFICATION_BODY = "Notification-body";
@@ -76,7 +75,7 @@ public void setup() throws Exception {
public void onOpened_noReactContext_launchApp() throws Exception {
when(mAppLifecycleFacade.isReactInitialized()).thenReturn(false);
- final PushNotification uut = createUUT();
+ final LocalNotification uut = createUUT();
uut.onOpened();
verify(mContext).startActivity(eq(mLaunchIntent));
@@ -93,17 +92,17 @@ public void onOpened_noReactContext_setAsInitialNotification() throws Exception
Activity currentActivity = mock(Activity.class);
when(mReactContext.getCurrentActivity()).thenReturn(currentActivity);
- final PushNotification uut = createUUT();
+ final LocalNotification uut = createUUT();
uut.onOpened();
- verify(InitialNotificationHolder.getInstance()).set(any(PushNotificationProps.class));
+ verify(InitialNotificationHolder.getInstance()).set(any(NotificationProps.class));
}
@Test
public void onOpened_appInvisible_resumeAppWaitForVisibility() throws Exception {
setUpBackgroundApp();
- final PushNotification uut = createUUT();
+ final LocalNotification uut = createUUT();
uut.onOpened();
verify(mContext).startActivity(any(Intent.class));
@@ -116,10 +115,10 @@ public void onOpened_appInvisible_dontSetInitialNotification() throws Exception
Activity currentActivity = mock(Activity.class);
when(mReactContext.getCurrentActivity()).thenReturn(currentActivity);
- final PushNotification uut = createUUT();
+ final LocalNotification uut = createUUT();
uut.onOpened();
- verify(InitialNotificationHolder.getInstance(), never()).set(any(PushNotificationProps.class));
+ verify(InitialNotificationHolder.getInstance(), never()).set(any(NotificationProps.class));
}
@Test
@@ -131,7 +130,7 @@ public void onOpened_appGoesVisible_resumeAppAndNotifyJs() throws Exception {
// Act
- final PushNotification uut = createUUT();
+ final LocalNotification uut = createUUT();
uut.onOpened();
// Hijack and invoke visibility listener
@@ -142,18 +141,18 @@ public void onOpened_appGoesVisible_resumeAppAndNotifyJs() throws Exception {
// Assert
- verify(mJsIOHelper).sendEventToJS(eq(NOTIFICATION_OPENED_EVENT_NAME), eq(mDefaultBundle), eq(mReactContext));
+ verify(mJsIOHelper).sendEventToJS(eq(NOTIFICATION_OPENED_EVENT_NAME), eq(mDefaultBundle));
}
@Test
public void onOpened_appVisible_notifyJS() throws Exception {
setUpForegroundApp();
- final PushNotification uut = createUUT();
+ final LocalNotification uut = createUUT();
uut.onOpened();
verify(mContext, never()).startActivity(any(Intent.class));
- verify(mJsIOHelper).sendEventToJS(eq(NOTIFICATION_OPENED_EVENT_NAME), eq(mDefaultBundle), eq(mReactContext));
+ verify(mJsIOHelper).sendEventToJS(eq(NOTIFICATION_OPENED_EVENT_NAME), eq(mDefaultBundle));
}
@Test
@@ -161,7 +160,7 @@ public void onOpened_appVisible_clearNotificationsDrawer() throws Exception {
verify(mNotificationManager, never()).cancelAll();
setUpForegroundApp();
- final PushNotification uut = createUUT();
+ final LocalNotification uut = createUUT();
uut.onOpened();
verify(mNotificationManager).cancelAll();
@@ -173,10 +172,10 @@ public void onOpened_appVisible_dontSetInitialNotification() throws Exception {
Activity currentActivity = mock(Activity.class);
when(mReactContext.getCurrentActivity()).thenReturn(currentActivity);
- final PushNotification uut = createUUT();
+ final LocalNotification uut = createUUT();
uut.onOpened();
- verify(InitialNotificationHolder.getInstance(), never()).set(any(PushNotificationProps.class));
+ verify(InitialNotificationHolder.getInstance(), never()).set(any(NotificationProps.class));
}
@Test
@@ -184,62 +183,10 @@ public void onOpened_reactInitializedWithNoActivities_setAsInitialNotification()
setUpBackgroundApp();
when(mReactContext.getCurrentActivity()).thenReturn(null); // Just for clarity
- final PushNotification uut = createUUT();
+ final LocalNotification uut = createUUT();
uut.onOpened();
- verify(InitialNotificationHolder.getInstance()).set(any(PushNotificationProps.class));
- }
-
- @Test
- public void onReceived_validData_postNotificationAndNotifyJS() throws Exception {
- // Arrange
-
- setUpForegroundApp();
-
- // Act
-
- final PushNotification uut = createUUT();
- uut.onReceived();
-
- // Assert
-
- ArgumentCaptor notificationCaptor = ArgumentCaptor.forClass(Notification.class);
- verify(mNotificationManager).notify(anyInt(), notificationCaptor.capture());
- verifyNotification(notificationCaptor.getValue());
-
- verify(mJsIOHelper).sendEventToJS(eq(NOTIFICATION_RECEIVED_EVENT_NAME), eq(mDefaultBundle), eq(mReactContext));
- }
-
- @Test
- public void onReceived_validDataForBackgroundApp_postNotificationAndNotifyJs() throws Exception {
- // Arrange
-
- setUpForegroundApp();
-
- // Act
-
- final PushNotification uut = createUUT();
- uut.onReceived();
-
- // Assert
-
- ArgumentCaptor notificationCaptor = ArgumentCaptor.forClass(Notification.class);
- verify(mNotificationManager).notify(anyInt(), notificationCaptor.capture());
- verifyNotification(notificationCaptor.getValue());
-
- verify(mJsIOHelper).sendEventToJS(eq(NOTIFICATION_RECEIVED_EVENT_NAME), eq(mDefaultBundle), eq(mReactContext));
- }
-
- @Test
- public void onReceived_validDataForDeadApp_postNotificationDontNotifyJS() throws Exception {
- final PushNotification uut = createUUT();
- uut.onReceived();
-
- ArgumentCaptor notificationCaptor = ArgumentCaptor.forClass(Notification.class);
- verify(mNotificationManager).notify(anyInt(), notificationCaptor.capture());
- verifyNotification(notificationCaptor.getValue());
-
- verify(mJsIOHelper, never()).sendEventToJS(eq(NOTIFICATION_RECEIVED_EVENT_NAME), any(Bundle.class), any(ReactContext.class));
+ verify(InitialNotificationHolder.getInstance()).set(any(NotificationProps.class));
}
@Test
@@ -251,8 +198,8 @@ public void onPostRequest_withValidDataButNoId_postNotifications() throws Except
// Act
- final PushNotification uut = createUUT();
- uut.onPostRequest(null);
+ final LocalNotification uut = createUUT();
+ uut.post(null);
// Assert
@@ -261,13 +208,13 @@ public void onPostRequest_withValidDataButNoId_postNotifications() throws Except
verifyNotification(notificationCaptor.getValue());
// Shouldn't notify an event on an explicit call to notification posting
- verify(mJsIOHelper, never()).sendEventToJS(eq(NOTIFICATION_RECEIVED_EVENT_NAME), any(Bundle.class), any(ReactContext.class));
+ verify(mJsIOHelper, never()).sendEventToJS(eq(NOTIFICATION_RECEIVED_EVENT_NAME), any(Bundle.class));
}
@Test
public void onPostRequest_withValidDataButNoId_idsShouldBeUnique() throws Exception {
- createUUT().onPostRequest(null);
- createUUT().onPostRequest(null);
+ createUUT().post(null);
+ createUUT().post(null);
ArgumentCaptor idsCaptor = ArgumentCaptor.forClass(Integer.class);
verify(mNotificationManager, times(2)).notify(idsCaptor.capture(), any(Notification.class));
@@ -278,26 +225,27 @@ public void onPostRequest_withValidDataButNoId_idsShouldBeUnique() throws Except
public void onPostRequest_withValidDataAndExplicitId_postNotification() throws Exception {
final int id = 666;
- final PushNotification uut = createUUT();
- uut.onPostRequest(id);
+ final LocalNotification uut = createUUT();
+ uut.post(id);
verify(mNotificationManager).notify(eq(id), any(Notification.class));
}
@Test
public void onPostRequest_emptyData_postNotification() throws Exception {
- PushNotification uut = createUUT(new Bundle());
- uut.onPostRequest(null);
+ LocalNotification uut = createUUT(new Bundle());
+ uut.post(null);
verify(mNotificationManager).notify(anyInt(), any(Notification.class));
}
- protected PushNotification createUUT() {
+ protected LocalNotification createUUT() {
return createUUT(mDefaultBundle);
}
- protected PushNotification createUUT(Bundle bundle) {
- return new PushNotification(mContext, bundle, mAppLifecycleFacade, mAppLaunchHelper, mJsIOHelper);
+ protected LocalNotification createUUT(Bundle bundle) {
+ final NotificationProps localNotificationProps = new NotificationProps(mContext, bundle);
+ return new LocalNotification(mContext, localNotificationProps, mAppLifecycleFacade, mAppLaunchHelper, mJsIOHelper);
}
protected void setUpBackgroundApp() {
diff --git a/android/src/test/java/com/wix/reactnativenotifications/core/notifications/RemoteNotificationTest.java b/android/src/test/java/com/wix/reactnativenotifications/core/notifications/RemoteNotificationTest.java
new file mode 100644
index 000000000..c2377d334
--- /dev/null
+++ b/android/src/test/java/com/wix/reactnativenotifications/core/notifications/RemoteNotificationTest.java
@@ -0,0 +1,60 @@
+package com.wix.reactnativenotifications.core.notifications;
+
+import android.content.Context;
+import android.os.Bundle;
+
+import com.wix.reactnativenotifications.core.JsIOHelper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+
+import static com.wix.reactnativenotifications.Defs.NOTIFICATION_RECEIVED_EVENT_NAME;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(RobolectricTestRunner.class)
+public class RemoteNotificationTest {
+
+ private static final String DEFAULT_NOTIFICATION_TITLE = "Notification-title";
+ private static final String DEFAULT_NOTIFICATION_BODY = "Notification-body";
+
+ @Mock private Context mContext;
+
+ @Mock private Bundle mDefaultBundle;
+ @Mock private JsIOHelper mJsIOHelper;
+
+ @Before
+ public void setup() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ when(mDefaultBundle.getString(eq("title"))).thenReturn(DEFAULT_NOTIFICATION_TITLE);
+ when(mDefaultBundle.getString(eq("body"))).thenReturn(DEFAULT_NOTIFICATION_BODY);
+ when(mDefaultBundle.clone()).thenReturn(mDefaultBundle);
+ }
+
+ @Test
+ public void onReceived_validData_postNotificationAndNotifyJS() throws Exception {
+ // Act
+
+ final RemoteNotification uut = createUUT();
+ uut.onReceived();
+
+ // Assert
+
+ verify(mJsIOHelper).sendEventToJS(eq(NOTIFICATION_RECEIVED_EVENT_NAME), eq(mDefaultBundle));
+ }
+
+ protected RemoteNotification createUUT() {
+ return createUUT(mDefaultBundle);
+ }
+
+ protected RemoteNotification createUUT(Bundle bundle) {
+ final NotificationProps notificationProps = new NotificationProps(mContext, bundle);
+ return new RemoteNotification(notificationProps, mJsIOHelper);
+ }
+}
diff --git a/android/src/test/java/com/wix/reactnativenotifications/fcm/FcmTokenBridgeTest.java b/android/src/test/java/com/wix/reactnativenotifications/fcm/FcmTokenBridgeTest.java
new file mode 100644
index 000000000..b3f687218
--- /dev/null
+++ b/android/src/test/java/com/wix/reactnativenotifications/fcm/FcmTokenBridgeTest.java
@@ -0,0 +1,57 @@
+package com.wix.reactnativenotifications.fcm;
+
+import android.content.Context;
+import android.os.Bundle;
+
+import com.google.firebase.iid.FirebaseInstanceId;
+import com.wix.reactnativenotifications.core.JsIOHelper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+
+import static com.wix.reactnativenotifications.Defs.TOKEN_RECEIVED_EVENT_NAME;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(RobolectricTestRunner.class)
+public class FcmTokenBridgeTest {
+
+ private static final String DEFAULT_NOTIFICATION_TITLE = "Notification-title";
+ private static final String DEFAULT_NOTIFICATION_BODY = "Notification-body";
+
+ @Mock private Context mContext;
+
+ @Mock private Bundle mDefaultBundle;
+ @Mock private FirebaseInstanceId mFirebaseInstanceId;
+ @Mock private JsIOHelper mJsIOHelper;
+
+ @Before
+ public void setup() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ when(mDefaultBundle.getString(eq("title"))).thenReturn(DEFAULT_NOTIFICATION_TITLE);
+ when(mDefaultBundle.getString(eq("body"))).thenReturn(DEFAULT_NOTIFICATION_BODY);
+ when(mDefaultBundle.clone()).thenReturn(mDefaultBundle);
+ }
+
+ @Test
+ public void refreshToken_notifyJs() throws Exception {
+ // Act
+
+ final FcmTokenBridge uut = createUUT();
+ uut.refreshToken();
+
+ // Assert
+
+ verify(mJsIOHelper).sendEventToJS(eq(TOKEN_RECEIVED_EVENT_NAME), eq(mDefaultBundle));
+ }
+
+ protected FcmTokenBridge createUUT() {
+ return new FcmTokenBridge(mFirebaseInstanceId, mJsIOHelper);
+ }
+}
diff --git a/example/index.android.js b/example/index.android.js
index 5681d187c..585cf8523 100644
--- a/example/index.android.js
+++ b/example/index.android.js
@@ -117,7 +117,7 @@ class MainComponent extends Component {
Wix React Native Notifications
{this.state.initialNotification ? 'Opened from notification' : ''}
- Last notification: {this.state.lastNotification ? '\n'+this.state.lastNotification.body + ` (opened at ''${this.state.notificationRxTime})` : "N/A"}
+ Last notification: {this.state.lastNotification ? '\n'+this.state.lastNotification.getBody() + ` (opened at ''${this.state.notificationRxTime})` : "N/A"}
Time elapsed: {this.state.elapsed}
{"\n\n"}
this.onPostNotification()}>
diff --git a/index.android.js b/index.android.js
index 03fbe0d45..8d2d604c1 100644
--- a/index.android.js
+++ b/index.android.js
@@ -45,14 +45,23 @@ export class NotificationsAndroid {
RNNotifications.refreshToken();
}
- static localNotification(notification: Object) {
- const id = Math.random() * 100000000 | 0; // Bitwise-OR forces value onto a 32bit limit
- RNNotifications.postLocalNotification(notification, id);
+ static localNotification(notification, id) {
+ const notificationProperties = notification instanceof NotificationAndroid ? notification.properties : notification;
+
+ if (!id && id !== 0) {
+ id = notificationProperties.tag ? 0 : Math.random() * 100000000 | 0; // Bitwise-OR forces value onto a 32bit limit
+ }
+
+ RNNotifications.postLocalNotification(notificationProperties, id);
return id;
}
- static cancelLocalNotification(id) {
- RNNotifications.cancelLocalNotification(id);
+ static cancelLocalNotification(id, tag) {
+ RNNotifications.cancelLocalNotification(id, tag);
+ }
+
+ static cancelAllLocalNotifications() {
+ RNNotifications.cancelAllLocalNotifications();
}
}
diff --git a/notification.android.js b/notification.android.js
index bb2ace85e..1aed2dab8 100644
--- a/notification.android.js
+++ b/notification.android.js
@@ -1,20 +1,46 @@
-/** A wrapper to align Android with iOS in terms on notification structure. */
+/** A wrapper to align Android with iOS in terms on notification structure and provide convenience methods. */
export default class NotificationAndroid {
- constructor(notification) {
- this.data = notification;
+ constructor(properties) {
+ this.properties = properties;
}
+ isDataOnly() {
+ return this.getData() && Object.keys(this.properties).length === 1;
+ }
+
+ // Convenience accessors
+
getData() {
- return this.data;
+ return this.properties.data;
}
getTitle() {
- return this.data.title;
+ return this.properties.title;
}
+ getBody() {
+ return this.properties.body;
+ }
+
+ // Alias for getBody()
getMessage() {
- return this.data.body;
+ return this.getBody();
+ }
+
+ getIcon() {
+ return this.properties.icon;
+ }
+
+ getSound() {
+ return this.properties.sound;
}
-}
+ getTag() {
+ return this.properties.tag;
+ }
+
+ getColor() {
+ return this.properties.color;
+ }
+}
diff --git a/test/index.android.spec.js b/test/index.android.spec.js
index a41255b81..96149b405 100644
--- a/test/index.android.spec.js
+++ b/test/index.android.spec.js
@@ -10,6 +10,7 @@ describe("Notifications-Android > ", () => {
let getInitialNotificationStub;
let postLocalNotificationStub;
let cancelLocalNotificationStub;
+ let cancelAllLocalNotificationsStub;
let deviceEventEmitterListenerStub;
let libUnderTest;
beforeEach(() => {
@@ -17,6 +18,7 @@ describe("Notifications-Android > ", () => {
getInitialNotificationStub = sinon.stub();
postLocalNotificationStub = sinon.stub();
cancelLocalNotificationStub = sinon.stub();
+ cancelAllLocalNotificationsStub = sinon.stub();
deviceEventEmitterListenerStub = sinon.stub();
libUnderTest = proxyquire("../index.android", {
@@ -26,7 +28,8 @@ describe("Notifications-Android > ", () => {
refreshToken: refreshTokenStub,
getInitialNotification: getInitialNotificationStub,
postLocalNotification: postLocalNotificationStub,
- cancelLocalNotification: cancelLocalNotificationStub
+ cancelLocalNotification: cancelLocalNotificationStub,
+ cancelAllLocalNotifications: cancelAllLocalNotificationsStub
}
},
DeviceEventEmitter: {
@@ -83,14 +86,15 @@ describe("Notifications-Android > ", () => {
it("should assign a wrapper-callback upon registration", () => {
expect(deviceEventEmitterListenerStub).to.not.have.been.called;
const userListenerStub = sinon.stub();
- const notification = { foo: "bar" };
+ const data = {foo: "bar"};
+ const notification = {data};
libUnderTest.NotificationsAndroid.setNotificationOpenedListener(userListenerStub);
expect(userListenerStub).to.not.have.been.called;
deviceEventEmitterListenerStub.args[0][1](notification);
expect(userListenerStub).to.have.been.calledOnce;
- expect(userListenerStub.args[0][0].getData()).to.equal(notification);
+ expect(userListenerStub.args[0][0].getData()).to.equal(data);
});
it("should clear native event listener upon listener deregister", () => {
@@ -128,14 +132,15 @@ describe("Notifications-Android > ", () => {
it("should assign a wrapper-callback upon registration", () => {
expect(deviceEventEmitterListenerStub).to.not.have.been.called;
const userListenerStub = sinon.stub();
- const notification = { foo: "bar" };
+ const data = {foo: "bar"};
+ const notification = {data};
libUnderTest.NotificationsAndroid.setNotificationReceivedListener(userListenerStub);
expect(userListenerStub).to.not.have.been.called;
deviceEventEmitterListenerStub.args[0][1](notification);
expect(userListenerStub).to.have.been.calledOnce;
- expect(userListenerStub.args[0][0].getData()).to.equal(notification);
+ expect(userListenerStub.args[0][0].getData()).to.equal(data);
});
it("should clear native event listener upon listener deregister", () => {
@@ -170,12 +175,13 @@ describe("Notifications-Android > ", () => {
describe("Initial notification API", () => {
it("should return initial notification data if available", (done) => {
expect(getInitialNotificationStub).to.not.have.been.called;
- const rawNotification = {foo: "bar"};
+ const data = {foo: "bar"};
+ const rawNotification = {data};
getInitialNotificationStub.returns(Promise.resolve(rawNotification));
libUnderTest.PendingNotifications.getInitialNotification()
.then((notification) => {
- expect(notification.getData()).to.equal(rawNotification);
+ expect(notification.getData()).to.equal(data);
done();
})
.catch((err) => done(err));
@@ -195,7 +201,7 @@ describe("Notifications-Android > ", () => {
});
- describe("Local notification", () => {
+ describe("Local notifications", () => {
const notification = {
title: "notification-title",
body: "notification-body"
@@ -209,7 +215,7 @@ describe("Notifications-Android > ", () => {
expect(postLocalNotificationStub).to.have.been.calledWith(notification, id);
});
- it("should be called with a unique ID", () => {
+ it("should be published with a unique ID", () => {
expect(postLocalNotificationStub).to.not.have.been.called;
const id = libUnderTest.NotificationsAndroid.localNotification(notification);
@@ -226,6 +232,14 @@ describe("Notifications-Android > ", () => {
expect(cancelLocalNotificationStub).to.have.been.calledWith(666);
});
+
+ it("should be cancellable", () => {
+ expect(cancelLocalNotificationStub).to.not.have.been.called;
+
+ libUnderTest.NotificationsAndroid.cancelAllLocalNotifications();
+
+ expect(cancelAllLocalNotificationsStub).to.have.been.called;
+ });
});
});