diff --git a/android/build.gradle b/android/build.gradle
index e412eeaf948772fbb6d63f13c1750e154f78619e..7be952cc49be85b7e43ae734b9f90ba7f27e6c56 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -16,10 +16,6 @@ android {
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
-
- testOptions {
- unitTests.returnDefaultValues = true
- }
}
dependencies {
@@ -30,4 +26,5 @@ dependencies {
testCompile 'junit:junit:4.12'
testCompile 'org.mockito:mockito-core:2.+'
+ testCompile "org.robolectric:robolectric:3.1.4"
}
diff --git a/android/src/main/java/com/wix/reactnativenotifications/core/RNNotificationsModule.java b/android/src/main/java/com/wix/reactnativenotifications/core/RNNotificationsModule.java
index 150196c47abcebef3edecf70fbf5bd7f5015c456..cb8935ba911fd544370eadc26b7a62113bf44edb 100644
--- a/android/src/main/java/com/wix/reactnativenotifications/core/RNNotificationsModule.java
+++ b/android/src/main/java/com/wix/reactnativenotifications/core/RNNotificationsModule.java
@@ -70,22 +70,15 @@ public class RNNotificationsModule extends ReactContextBaseJavaModule implements
}
@ReactMethod
- public void postLocalNotification(ReadableMap notificationPropsMap, final Promise promise) {
+ public void postLocalNotification(ReadableMap notificationPropsMap, int notificationId) {
Log.d(LOGTAG, "Native method invocation: postLocalNotification");
- Object result = null;
-
- try {
- final Bundle notificationProps = Arguments.toBundle(notificationPropsMap);
- final IPushNotification pushNotification = PushNotification.get(getReactApplicationContext().getApplicationContext(), notificationProps, ReactAppLifecycleFacade.get());
- int id = pushNotification.onPostRequest();
- result = id;
- } finally {
- promise.resolve(result);
- }
+ final Bundle notificationProps = Arguments.toBundle(notificationPropsMap);
+ final IPushNotification pushNotification = PushNotification.get(getReactApplicationContext().getApplicationContext(), notificationProps, ReactAppLifecycleFacade.get());
+ pushNotification.onPostRequest(notificationId);
}
@ReactMethod
- public void removeLocalNotification(int notificationId) {
+ public void cancelLocalNotification(int notificationId) {
IPushNotificationsDrawer notificationsDrawer = PushNotificationsDrawer.get(getReactApplicationContext().getApplicationContext());
notificationsDrawer.onNotificationClear(notificationId);
}
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
index 46f1015d59f84acd2feceee1f791451cec7a0098..0d70024acb10a42280c030892eea5b3df0e81624 100644
--- a/android/src/main/java/com/wix/reactnativenotifications/core/notification/IPushNotification.java
+++ b/android/src/main/java/com/wix/reactnativenotifications/core/notification/IPushNotification.java
@@ -20,9 +20,11 @@ public interface IPushNotification {
/**
* Handle a request to post this notification.
- * @return ID to optionally use for notification deletion.
+ *
+ * @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();
+ int onPostRequest(Integer notificationId);
PushNotificationProps asProps();
}
diff --git a/android/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java b/android/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java
index 4d1715ff6f7bb8192b4124d105baa9eee672b4cc..5bc7db29ae58aa91fef5afc28c2a66209d40e350 100644
--- a/android/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java
+++ b/android/src/main/java/com/wix/reactnativenotifications/core/notification/PushNotification.java
@@ -7,13 +7,7 @@ import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
-import com.facebook.react.ReactApplication;
-import com.facebook.react.ReactInstanceManager;
-import com.facebook.react.ReactNativeHost;
-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;
import com.wix.reactnativenotifications.core.AppLaunchHelper;
import com.wix.reactnativenotifications.core.AppLifecycleFacade;
import com.wix.reactnativenotifications.core.AppLifecycleFacade.AppVisibilityListener;
@@ -66,7 +60,7 @@ public class PushNotification implements IPushNotification {
@Override
public void onReceived() throws InvalidNotificationException {
- postNotification();
+ postNotification(null);
notifyReceivedToJS();
}
@@ -76,8 +70,8 @@ public class PushNotification implements IPushNotification {
}
@Override
- public int onPostRequest() {
- return postNotification();
+ public int onPostRequest(Integer notificationId) {
+ return postNotification(notificationId);
}
@Override
@@ -85,10 +79,10 @@ public class PushNotification implements IPushNotification {
return mNotificationProps.copy();
}
- protected int postNotification() {
+ protected int postNotification(Integer notificationId) {
final PendingIntent pendingIntent = getCTAPendingIntent();
final Notification notification = buildNotification(pendingIntent);
- return postNotification(notification);
+ return postNotification(notification, notificationId);
}
protected void digestNotification() {
@@ -153,8 +147,8 @@ public class PushNotification implements IPushNotification {
.setAutoCancel(true);
}
- protected int postNotification(Notification notification) {
- int id = createNotificationId(notification);
+ protected int postNotification(Notification notification, Integer notificationId) {
+ int id = notificationId != null ? notificationId : createNotificationId(notification);
postNotification(id, notification);
return id;
}
diff --git a/android/src/test/java/com/wix/reactnativenotifications/core/notification/PushNotificationTest.java b/android/src/test/java/com/wix/reactnativenotifications/core/notification/PushNotificationTest.java
index bde7d32d10c34971c86733f730abe9b88d0f6f32..99fde0dd81ac76b4b6a560df90cc6c9500f79256 100644
--- a/android/src/test/java/com/wix/reactnativenotifications/core/notification/PushNotificationTest.java
+++ b/android/src/test/java/com/wix/reactnativenotifications/core/notification/PushNotificationTest.java
@@ -15,7 +15,9 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
+import org.robolectric.RobolectricTestRunner;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
@@ -23,9 +25,12 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-@RunWith(MockitoJUnitRunner.Silent.class)
+@RunWith(RobolectricTestRunner.class)
public class PushNotificationTest {
+ private static final String NOTIFICATION_OPENED_EVENT_NAME = "notificationOpened";
+ private static final String NOTIFICATION_RECEIVED_EVENT_NAME = "notificationReceived";
+
@Mock private ReactContext mReactContext;
@Mock private Context mContext;
@@ -37,6 +42,8 @@ public class PushNotificationTest {
@Before
public void setup() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
when(mDefaultBundle.getString(eq("title"))).thenReturn("Notification-title");
when(mDefaultBundle.getString(eq("body"))).thenReturn("Notification-body");
when(mDefaultBundle.clone()).thenReturn(mDefaultBundle);
@@ -88,7 +95,7 @@ public class PushNotificationTest {
// Assert
- verify(mReactContextAdapter).sendEventToJS(eq("notificationOpened"), eq(mDefaultBundle), eq(mContext));
+ verify(mReactContextAdapter).sendEventToJS(eq(NOTIFICATION_OPENED_EVENT_NAME), eq(mDefaultBundle), eq(mContext));
}
@Test
@@ -100,7 +107,15 @@ public class PushNotificationTest {
uut.onOpened();
verify(mContext, never()).startActivity(any(Intent.class));
- verify(mReactContextAdapter).sendEventToJS(eq("notificationOpened"), eq(mDefaultBundle), eq(mContext));
+ verify(mReactContextAdapter).sendEventToJS(eq(NOTIFICATION_OPENED_EVENT_NAME), eq(mDefaultBundle), eq(mContext));
+ }
+
+ @Test
+ public void onPostRequest_withValidDataButNoId_postNotifAndNotifyJS() throws Exception {
+ final PushNotification uut = createUUT();
+ uut.onPostRequest(null);
+
+ verify(mReactContextAdapter).sendEventToJS(eq(NOTIFICATION_RECEIVED_EVENT_NAME), eq(mDefaultBundle), eq(mContext));
}
protected PushNotification createUUT() {
diff --git a/example/android/myapplication/src/main/AndroidManifest.xml b/example/android/myapplication/src/main/AndroidManifest.xml
index 214751cac600ef8a87168b9eaf0496b3bf2c52e6..3df23d464dc64562b5bc9578f41bfe28c284a706 100644
--- a/example/android/myapplication/src/main/AndroidManifest.xml
+++ b/example/android/myapplication/src/main/AndroidManifest.xml
@@ -24,11 +24,6 @@
-
-
-
diff --git a/example/index.android.js b/example/index.android.js
index b0af4b48f3fc411cc4a36de8c1f478b3fe29cb83..24274b15a123906afc0ccca6e71e6a2fdfb9ae16 100644
--- a/example/index.android.js
+++ b/example/index.android.js
@@ -5,7 +5,8 @@ import {
AppRegistry,
StyleSheet,
Text,
- View
+ View,
+ TouchableHighlight
} from 'react-native';
import {NotificationsAndroid, PendingNotifications} from 'react-native-notifications';
@@ -42,7 +43,7 @@ const styles = StyleSheet.create({
justifyContent: 'center',
},
titleText: {
- fontSize: 22,
+ fontSize: 24,
textAlign: 'center',
margin: 10,
},
@@ -51,6 +52,19 @@ const styles = StyleSheet.create({
textAlign: 'center',
margin: 10,
},
+ mainButtonText: {
+ fontSize: 25,
+ fontStyle: 'italic',
+ fontWeight: 'bold',
+ textAlign: 'center',
+ margin: 10,
+ },
+ plainButtonText: {
+ fontSize: 18,
+ fontStyle: 'italic',
+ textAlign: 'center',
+ margin: 10,
+ },
});
class MainComponent extends Component {
@@ -58,6 +72,9 @@ class MainComponent extends Component {
constructor(props) {
super(props);
+ this.onPostNotification = this.onPostNotification.bind(this);
+ this.onCancelNotification = this.onCancelNotification.bind(this);
+
this.state = {
elapsed: 0,
lastNotification: undefined
@@ -84,6 +101,17 @@ class MainComponent extends Component {
this.setState({elapsed: this.state.elapsed + 1});
}
+ onPostNotification() {
+ this.lastNotificationId = NotificationsAndroid.localNotification({title: "Local notification", body: "This notification was generated by the app!"});
+ }
+
+ onCancelNotification() {
+ if (this.lastNotificationId) {
+ NotificationsAndroid.cancelLocalNotification(this.lastNotificationId);
+ this.lastNotificationId = undefined;
+ }
+ }
+
render() {
return (
@@ -91,6 +119,13 @@ class MainComponent extends Component {
{this.state.initialNotification ? 'Opened from notification' : ''}
Last notification: {this.state.lastNotification ? '\n'+this.state.lastNotification.body + ` (opened at ''${this.state.notificationRxTime})` : "N/A"}
Time elapsed: {this.state.elapsed}
+ {"\n\n"}
+ this.onPostNotification()}>
+ Try Me!
+
+ this.onCancelNotification()}>
+ Undo last
+
)
}
diff --git a/index.android.js b/index.android.js
index f78dc231e275281d463a106b5ece8aeadd428195..e98936d8c4c3e0b6266cd241e1fee9ff9b5060fd 100644
--- a/index.android.js
+++ b/index.android.js
@@ -44,6 +44,16 @@ export class NotificationsAndroid {
static refreshToken() {
RNNotifications.refreshToken();
}
+
+ static localNotification(notification: Object) {
+ const id = Date.now() | 0; // Bitwise-OR forces value onto a 32bit limit
+ RNNotifications.postLocalNotification(notification, id);
+ return id;
+ }
+
+ static cancelLocalNotification(id) {
+ RNNotifications.cancelLocalNotification(id);
+ }
}
export class PendingNotifications {
diff --git a/test/index.android.spec.js b/test/index.android.spec.js
index 4462924b113cb2ad14d65ae9743d8ac0e5330f47..d471737551ae1f0a62622fe67b6ba782e097e5cc 100644
--- a/test/index.android.spec.js
+++ b/test/index.android.spec.js
@@ -3,16 +3,20 @@ let expect = require("chai").use(require("sinon-chai")).expect;
import proxyquire from "proxyquire";
import sinon from "sinon";
-describe("Notifications-Android", () => {
+describe("Notifications-Android > ", () => {
proxyquire.noCallThru();
let refreshTokenStub;
let getInitialNotificationStub;
+ let postLocalNotificationStub;
+ let cancelLocalNotificationStub;
let deviceEventEmitterListenerStub;
let libUnderTest;
beforeEach(() => {
refreshTokenStub = sinon.stub();
getInitialNotificationStub = sinon.stub();
+ postLocalNotificationStub = sinon.stub();
+ cancelLocalNotificationStub = sinon.stub();
deviceEventEmitterListenerStub = sinon.stub();
libUnderTest = proxyquire("../index.android", {
@@ -20,7 +24,9 @@ describe("Notifications-Android", () => {
NativeModules: {
WixRNNotifications: {
refreshToken: refreshTokenStub,
- getInitialNotification: getInitialNotificationStub
+ getInitialNotification: getInitialNotificationStub,
+ postLocalNotification: postLocalNotificationStub,
+ cancelLocalNotification: cancelLocalNotificationStub
}
},
DeviceEventEmitter: {
@@ -153,10 +159,12 @@ describe("Notifications-Android", () => {
});
});
- it("should refresh notification token upon refreshing request by the user", () => {
- expect(refreshTokenStub).to.not.have.been.called;
- libUnderTest.NotificationsAndroid.refreshToken();
- expect(refreshTokenStub).to.have.been.calledOnce;
+ describe("Notification token", () => {
+ it("should refresh notification token upon refreshing request by the user", () => {
+ expect(refreshTokenStub).to.not.have.been.called;
+ libUnderTest.NotificationsAndroid.refreshToken();
+ expect(refreshTokenStub).to.have.been.calledOnce;
+ });
});
describe("Initial notification API", () => {
@@ -187,4 +195,37 @@ describe("Notifications-Android", () => {
});
+ describe("Local notification", () => {
+ const notification = {
+ title: "notification-title",
+ body: "notification-body"
+ };
+
+ it("should get published when posted manually", () => {
+ expect(postLocalNotificationStub).to.not.have.been.called;
+
+ const id = libUnderTest.NotificationsAndroid.localNotification(notification);
+ expect(id).to.not.be.undefined;
+ expect(postLocalNotificationStub).to.have.been.calledWith(notification, id);
+ });
+
+ it("should be called with a unique ID", () => {
+ expect(postLocalNotificationStub).to.not.have.been.called;
+
+ const id = libUnderTest.NotificationsAndroid.localNotification(notification);
+ const id2 = libUnderTest.NotificationsAndroid.localNotification(notification);
+ expect(id).to.not.be.undefined;
+ expect(id2).to.not.be.undefined;
+ expect(id).to.not.equal(id2);
+ });
+
+ it("should be cancellable with an ID", () => {
+ expect(cancelLocalNotificationStub).to.not.have.been.called;
+
+ libUnderTest.NotificationsAndroid.cancelLocalNotification(666);
+
+ expect(cancelLocalNotificationStub).to.have.been.calledWith(666);
+ });
+ });
+
});