diff --git a/briar-android/res/drawable-hdpi/message_notification_icon.png b/briar-android/res/drawable-hdpi/message_notification_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..082c1000ac6087199b68fd43f6e4851691199ee7
Binary files /dev/null and b/briar-android/res/drawable-hdpi/message_notification_icon.png differ
diff --git a/briar-android/res/drawable-hdpi/notification_icon.png b/briar-android/res/drawable-hdpi/ongoing_notification_icon.png
similarity index 100%
rename from briar-android/res/drawable-hdpi/notification_icon.png
rename to briar-android/res/drawable-hdpi/ongoing_notification_icon.png
diff --git a/briar-android/res/drawable-ldpi/message_notification_icon.png b/briar-android/res/drawable-ldpi/message_notification_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..a88b8f5611705e61713160235273b102a42850a4
Binary files /dev/null and b/briar-android/res/drawable-ldpi/message_notification_icon.png differ
diff --git a/briar-android/res/drawable-ldpi/notification_icon.png b/briar-android/res/drawable-ldpi/ongoing_notification_icon.png
similarity index 100%
rename from briar-android/res/drawable-ldpi/notification_icon.png
rename to briar-android/res/drawable-ldpi/ongoing_notification_icon.png
diff --git a/briar-android/res/drawable-mdpi/message_notification_icon.png b/briar-android/res/drawable-mdpi/message_notification_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..e2d666cc7241b8ade31d14e9bb5bbbad52b5bae2
Binary files /dev/null and b/briar-android/res/drawable-mdpi/message_notification_icon.png differ
diff --git a/briar-android/res/drawable-mdpi/notification_icon.png b/briar-android/res/drawable-mdpi/ongoing_notification_icon.png
similarity index 100%
rename from briar-android/res/drawable-mdpi/notification_icon.png
rename to briar-android/res/drawable-mdpi/ongoing_notification_icon.png
diff --git a/briar-android/res/drawable-xhdpi/message_notification_icon.png b/briar-android/res/drawable-xhdpi/message_notification_icon.png
new file mode 100644
index 0000000000000000000000000000000000000000..b965d932070a7406007e746e9c5266f9de9031c1
Binary files /dev/null and b/briar-android/res/drawable-xhdpi/message_notification_icon.png differ
diff --git a/briar-android/res/drawable-xhdpi/notification_icon.png b/briar-android/res/drawable-xhdpi/ongoing_notification_icon.png
similarity index 100%
rename from briar-android/res/drawable-xhdpi/notification_icon.png
rename to briar-android/res/drawable-xhdpi/ongoing_notification_icon.png
diff --git a/briar-android/res/values/strings.xml b/briar-android/res/values/strings.xml
index 9920a91944c3dabae28c431adf5c4e5d68d8404c..f620adeef5986612c7fe0a47a5f75447d0ff8ec3 100644
--- a/briar-android/res/values/strings.xml
+++ b/briar-android/res/values/strings.xml
@@ -1,8 +1,8 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources>
     <string name="app_name">Briar</string>
-    <string name="notification_title">Briar is running</string>
-    <string name="notification_text">Touch to show the home screen.</string>
+    <string name="ongoing_notification_title">Briar is running</string>
+    <string name="ongoing_notification_text">Touch to show the home screen.</string>
     <string name="setup_title">Briar Setup</string>
     <string name="choose_nickname">Choose your nickname:</string>
     <string name="choose_password">Choose your password:</string>
@@ -91,4 +91,8 @@
     <string name="message_sent_toast">Message sent</string>
     <string name="post_sent_toast">Post sent</string>
     <string name="not_implemented_toast">Not implemented yet!</string>
+    <string name="private_message_notification_title">New private message</string>
+    <string name="private_message_notification_text">Touch to show.</string>
+    <string name="group_post_notification_title">New forum post</string>
+    <string name="group_post_notification_text">Touch to show.</string>
 </resources>
\ No newline at end of file
diff --git a/briar-android/src/org/briarproject/android/BriarService.java b/briar-android/src/org/briarproject/android/BriarService.java
index f0a82a053bcbe2da6cffc250c3abc7cc856d1165..96de8c0795eacedc65475a4f3e4bce9485620f15 100644
--- a/briar-android/src/org/briarproject/android/BriarService.java
+++ b/briar-android/src/org/briarproject/android/BriarService.java
@@ -1,9 +1,11 @@
 package org.briarproject.android;
 
+import static android.app.Notification.DEFAULT_ALL;
 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
 import static java.util.logging.Level.INFO;
+import static java.util.logging.Level.WARNING;
 
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
@@ -13,27 +15,36 @@ import java.util.logging.Logger;
 import javax.inject.Inject;
 
 import org.briarproject.R;
+import org.briarproject.android.contact.ContactListActivity;
+import org.briarproject.android.groups.GroupListActivity;
+import org.briarproject.api.ContactId;
 import org.briarproject.api.android.AndroidExecutor;
 import org.briarproject.api.android.DatabaseUiExecutor;
 import org.briarproject.api.db.DatabaseComponent;
 import org.briarproject.api.db.DatabaseConfig;
+import org.briarproject.api.db.DbException;
+import org.briarproject.api.event.Event;
+import org.briarproject.api.event.EventListener;
+import org.briarproject.api.event.MessageAddedEvent;
 import org.briarproject.api.lifecycle.LifecycleManager;
+import org.briarproject.api.messaging.GroupId;
 
 import roboguice.service.RoboService;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.content.ComponentName;
-import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
 import android.os.Binder;
 import android.os.IBinder;
 import android.support.v4.app.NotificationCompat;
 
-public class BriarService extends RoboService {
+public class BriarService extends RoboService implements EventListener {
 
 	private static final int ONGOING_NOTIFICATION_ID = 1;
 	private static final int FAILURE_NOTIFICATION_ID = 2;
+	private static final int PRIVATE_MESSAGE_NOTIFICATION_ID = 3;
+	private static final int GROUP_POST_NOTIFICATION_ID = 4;
 
 	private static final Logger LOG =
 			Logger.getLogger(BriarService.class.getName());
@@ -66,9 +77,9 @@ public class BriarService extends RoboService {
 		}
 		// Show an ongoing notification that the service is running
 		NotificationCompat.Builder b = new NotificationCompat.Builder(this);
-		b.setSmallIcon(R.drawable.notification_icon);
-		b.setContentTitle(getText(R.string.notification_title));
-		b.setContentText(getText(R.string.notification_text));
+		b.setSmallIcon(R.drawable.ongoing_notification_icon);
+		b.setContentTitle(getText(R.string.ongoing_notification_title));
+		b.setContentText(getText(R.string.ongoing_notification_text));
 		b.setWhen(0); // Don't show the time
 		b.setOngoing(true);
 		Intent i = new Intent(this, HomeScreenActivity.class);
@@ -81,6 +92,7 @@ public class BriarService extends RoboService {
 			@Override
 			public void run() {
 				if(lifecycleManager.startServices()) {
+					db.addListener(BriarService.this);
 					started = true;
 				} else {
 					if(LOG.isLoggable(INFO)) LOG.info("Startup failed");
@@ -99,7 +111,7 @@ public class BriarService extends RoboService {
 		Intent i = new Intent(this, HomeScreenActivity.class);
 		i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TOP);
 		b.setContentIntent(PendingIntent.getActivity(this, 0, i, 0));
-		Object o = getSystemService(Context.NOTIFICATION_SERVICE);
+		Object o = getSystemService(NOTIFICATION_SERVICE);
 		NotificationManager nm = (NotificationManager) o;
 		nm.notify(FAILURE_NOTIFICATION_ID, b.build());
 		// Bring HomeScreenActivity to the front to clear all other activities
@@ -130,11 +142,73 @@ public class BriarService extends RoboService {
 			@Override
 			public void run() {
 				androidExecutor.shutdown();
-				if(started) lifecycleManager.stopServices();
+				if(started) {
+					db.removeListener(BriarService.this);
+					lifecycleManager.stopServices();
+				}
 			}
 		}.start();
 	}
 
+	public void eventOccurred(Event e) {
+		if(e instanceof MessageAddedEvent) {
+			MessageAddedEvent m = (MessageAddedEvent) e;
+			GroupId g = m.getGroup().getId();
+			ContactId c = m.getContactId();
+			if(c != null) showMessageNotification(g, c);
+		}
+	}
+
+	private void showMessageNotification(final GroupId g, final ContactId c) {
+		dbUiExecutor.execute(new Runnable() {
+			public void run() {
+				try {
+					lifecycleManager.waitForDatabase();
+					if(g.equals(db.getInboxGroupId(c)))
+						showPrivateMessageNotification();
+					else showGroupPostNotification();
+				} catch(DbException e) {
+					if(LOG.isLoggable(WARNING))
+						LOG.log(WARNING, e.toString(), e);
+				} catch(InterruptedException e) {
+					if(LOG.isLoggable(INFO))
+						LOG.info("Interruped while waiting for database");
+					Thread.currentThread().interrupt();
+				}
+			}
+		});
+	}
+
+	private void showPrivateMessageNotification() {
+		NotificationCompat.Builder b = new NotificationCompat.Builder(this);
+		b.setSmallIcon(R.drawable.message_notification_icon);
+		b.setContentTitle(getText(R.string.private_message_notification_title));
+		b.setContentText(getText(R.string.private_message_notification_text));
+		b.setAutoCancel(true);
+		b.setDefaults(DEFAULT_ALL);
+		Intent i = new Intent(this, ContactListActivity.class);
+		i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_SINGLE_TOP);
+		b.setContentIntent(PendingIntent.getActivity(this, 0, i, 0));
+		Object o = getSystemService(NOTIFICATION_SERVICE);
+		NotificationManager nm = (NotificationManager) o;
+		nm.notify(PRIVATE_MESSAGE_NOTIFICATION_ID, b.build());
+	}
+
+	private void showGroupPostNotification() {
+		NotificationCompat.Builder b = new NotificationCompat.Builder(this);
+		b.setSmallIcon(R.drawable.message_notification_icon);
+		b.setContentTitle(getText(R.string.group_post_notification_title));
+		b.setContentText(getText(R.string.group_post_notification_text));
+		b.setAutoCancel(true);
+		b.setDefaults(DEFAULT_ALL);
+		Intent i = new Intent(this, GroupListActivity.class);
+		i.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_SINGLE_TOP);
+		b.setContentIntent(PendingIntent.getActivity(this, 0, i, 0));
+		Object o = getSystemService(NOTIFICATION_SERVICE);
+		NotificationManager nm = (NotificationManager) o;
+		nm.notify(GROUP_POST_NOTIFICATION_ID, b.build());
+	}
+
 	/** Waits for the database to be opened before returning. */
 	public void waitForDatabase() throws InterruptedException {
 		lifecycleManager.waitForDatabase();
diff --git a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
index ded5cf3cdab5dde1828d4f26e35d8b9ff703ec19..b2d4ea85b5e5c4ff4a2573e95b8ae811a6c4b614 100644
--- a/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
+++ b/briar-android/src/org/briarproject/android/contact/ConversationActivity.java
@@ -185,7 +185,6 @@ implements EventListener, OnClickListener, OnItemClickListener {
 		super.onActivityResult(request, result, data);
 		if(request == REQUEST_READ_MESSAGE && result == RESULT_PREV_NEXT) {
 			int position = data.getIntExtra("briar.POSITION", -1);
-			if(position == -1) throw new IllegalStateException();
 			if(position >= 0 && position < adapter.getCount())
 				displayMessage(position);
 		}
diff --git a/briar-android/src/org/briarproject/android/groups/GroupActivity.java b/briar-android/src/org/briarproject/android/groups/GroupActivity.java
index 506f16a52ec82e1455426a3929211560ad8c35f6..ff9970b7c0700816f3ba576ac406eb1ed993df21 100644
--- a/briar-android/src/org/briarproject/android/groups/GroupActivity.java
+++ b/briar-android/src/org/briarproject/android/groups/GroupActivity.java
@@ -173,7 +173,6 @@ OnClickListener, OnItemClickListener {
 		super.onActivityResult(request, result, data);
 		if(request == REQUEST_READ_POST && result == RESULT_PREV_NEXT) {
 			int position = data.getIntExtra("briar.POSITION", -1);
-			if(position == -1) throw new IllegalStateException();
 			if(position >= 0 && position < adapter.getCount())
 				displayMessage(position);
 		}