diff --git a/briar-android/src/main/AndroidManifest.xml b/briar-android/src/main/AndroidManifest.xml
index cadb8490399fd28f2f684339c455649753cbd899..c43e5aa27c3b6250bdcb4385fc02dbda64c52ea0 100644
--- a/briar-android/src/main/AndroidManifest.xml
+++ b/briar-android/src/main/AndroidManifest.xml
@@ -32,6 +32,11 @@
 			</intent-filter>
 		</service>
 
+		<service
+			android:name="org.briarproject.briar.android.NotificationCleanupService"
+			android:exported="false">
+		</service>
+
 		<activity
 			android:name="org.briarproject.briar.android.reporting.DevReportActivity"
 			android:excludeFromRecents="true"
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java
index 25d553bbeb8fb36a362ebbad1496d8c5db4bc53c..652ef527d4325294c8e9c69eb4ea4877ad501e25 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/AndroidComponent.java
@@ -151,6 +151,8 @@ public interface AndroidComponent
 
 	void inject(RecentEmojiPageModel recentEmojiPageModel);
 
+	void inject(NotificationCleanupService notificationCleanupService);
+
 	// Eager singleton load
 	void inject(AppModule.EagerSingletons init);
 }
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/AndroidNotificationManagerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/AndroidNotificationManagerImpl.java
index 6b4df66c50e0a2c803c92c23ac75836b5ec431e2..329f7b9968433d9a064e12cd81cfd635a66eab86 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/AndroidNotificationManagerImpl.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/AndroidNotificationManagerImpl.java
@@ -2,6 +2,7 @@ package org.briarproject.briar.android;
 
 import android.app.Application;
 import android.app.NotificationManager;
+import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
@@ -83,16 +84,6 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
 	private static final int BLOG_POST_NOTIFICATION_ID = 6;
 	private static final int INTRODUCTION_SUCCESS_NOTIFICATION_ID = 7;
 
-	// Content URIs to differentiate between pending intents
-	private static final String CONTACT_URI =
-			"content://org.briarproject.briar/contact";
-	private static final String GROUP_URI =
-			"content://org.briarproject.briar/group";
-	private static final String FORUM_URI =
-			"content://org.briarproject.briar/forum";
-	private static final String BLOG_URI =
-			"content://org.briarproject.briar/blog";
-
 	private static final long SOUND_DELAY = TimeUnit.SECONDS.toMillis(2);
 
 	private static final Logger LOG =
@@ -268,7 +259,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
 				if (count == null) contactCounts.put(c, 1);
 				else contactCounts.put(c, count + 1);
 				contactTotal++;
-				updateContactNotification();
+				updateContactNotification(true);
 			}
 		});
 	}
@@ -281,13 +272,13 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
 				Integer count = contactCounts.remove(c);
 				if (count == null) return; // Already cleared
 				contactTotal -= count;
-				updateContactNotification();
+				updateContactNotification(false);
 			}
 		});
 	}
 
 	@UiThread
-	private void updateContactNotification() {
+	private void updateContactNotification(boolean mayAlertAgain) {
 		if (contactTotal == 0) {
 			clearContactNotification();
 		} else if (settings.getBoolean(PREF_NOTIFY_PRIVATE, true)) {
@@ -303,7 +294,8 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
 			boolean showOnLockScreen =
 					settings.getBoolean(PREF_NOTIFY_LOCK_SCREEN, false);
 			b.setLockscreenVisibility(CATEGORY_MESSAGE, showOnLockScreen);
-			playSound(b);
+			if (mayAlertAgain) setAlertProperties(b);
+			setDeleteIntent(b, CONTACT_URI);
 			if (contactCounts.size() == 1) {
 				// Touching the notification shows the relevant conversation
 				Intent i = new Intent(appContext, ConversationActivity.class);
@@ -333,17 +325,15 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
 	}
 
 	@UiThread
-	private void playSound(BriarNotificationBuilder b) {
-		boolean sound = settings.getBoolean(PREF_NOTIFY_SOUND, true);
-		if (!sound) return;
-
+	private void setAlertProperties(BriarNotificationBuilder b) {
 		long currentTime = clock.currentTimeMillis();
 		if (currentTime - lastSound > SOUND_DELAY) {
+			boolean sound = settings.getBoolean(PREF_NOTIFY_SOUND, true);
 			String ringtoneUri = settings.get(PREF_NOTIFY_RINGTONE_URI);
-			if (!StringUtils.isNullOrEmpty(ringtoneUri))
+			if (sound && !StringUtils.isNullOrEmpty(ringtoneUri))
 				b.setSound(Uri.parse(ringtoneUri));
 			b.setDefaults(getDefaults());
-			lastSound = clock.currentTimeMillis();
+			lastSound = currentTime;
 		}
 	}
 
@@ -359,6 +349,23 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
 		return defaults;
 	}
 
+	private void setDeleteIntent(BriarNotificationBuilder b, String uri) {
+		Intent i = new Intent(appContext, NotificationCleanupService.class);
+		i.setData(Uri.parse(uri));
+		b.setDeleteIntent(PendingIntent.getService(appContext, nextRequestId++,
+				i, 0));
+	}
+
+	@Override
+	public void clearAllContactNotifications() {
+		androidExecutor.runOnUiThread(new Runnable() {
+			@Override
+			public void run() {
+				clearContactNotification();
+			}
+		});
+	}
+
 	@UiThread
 	private void showGroupMessageNotification(final GroupId g) {
 		androidExecutor.runOnUiThread(new Runnable() {
@@ -370,7 +377,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
 				if (count == null) groupCounts.put(g, 1);
 				else groupCounts.put(g, count + 1);
 				groupTotal++;
-				updateGroupMessageNotification();
+				updateGroupMessageNotification(true);
 			}
 		});
 	}
@@ -383,13 +390,13 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
 				Integer count = groupCounts.remove(g);
 				if (count == null) return; // Already cleared
 				groupTotal -= count;
-				updateGroupMessageNotification();
+				updateGroupMessageNotification(false);
 			}
 		});
 	}
 
 	@UiThread
-	private void updateGroupMessageNotification() {
+	private void updateGroupMessageNotification(boolean mayAlertAgain) {
 		if (groupTotal == 0) {
 			clearGroupMessageNotification();
 		} else if (settings.getBoolean(PREF_NOTIFY_GROUP, true)) {
@@ -405,7 +412,8 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
 			boolean showOnLockScreen =
 					settings.getBoolean(PREF_NOTIFY_LOCK_SCREEN, false);
 			b.setLockscreenVisibility(CATEGORY_SOCIAL, showOnLockScreen);
-			playSound(b);
+			if (mayAlertAgain) setAlertProperties(b);
+			setDeleteIntent(b, GROUP_URI);
 			if (groupCounts.size() == 1) {
 				// Touching the notification shows the relevant group
 				Intent i = new Intent(appContext, GroupActivity.class);
@@ -435,6 +443,16 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
 		}
 	}
 
+	@Override
+	public void clearAllGroupMessageNotifications() {
+		androidExecutor.runOnUiThread(new Runnable() {
+			@Override
+			public void run() {
+				clearGroupMessageNotification();
+			}
+		});
+	}
+
 	@UiThread
 	private void showForumPostNotification(final GroupId g) {
 		androidExecutor.runOnUiThread(new Runnable() {
@@ -446,7 +464,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
 				if (count == null) forumCounts.put(g, 1);
 				else forumCounts.put(g, count + 1);
 				forumTotal++;
-				updateForumPostNotification();
+				updateForumPostNotification(true);
 			}
 		});
 	}
@@ -459,13 +477,13 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
 				Integer count = forumCounts.remove(g);
 				if (count == null) return; // Already cleared
 				forumTotal -= count;
-				updateForumPostNotification();
+				updateForumPostNotification(false);
 			}
 		});
 	}
 
 	@UiThread
-	private void updateForumPostNotification() {
+	private void updateForumPostNotification(boolean mayAlertAgain) {
 		if (forumTotal == 0) {
 			clearForumPostNotification();
 		} else if (settings.getBoolean(PREF_NOTIFY_FORUM, true)) {
@@ -481,7 +499,8 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
 			boolean showOnLockScreen =
 					settings.getBoolean(PREF_NOTIFY_LOCK_SCREEN, false);
 			b.setLockscreenVisibility(CATEGORY_SOCIAL, showOnLockScreen);
-			playSound(b);
+			if (mayAlertAgain) setAlertProperties(b);
+			setDeleteIntent(b, FORUM_URI);
 			if (forumCounts.size() == 1) {
 				// Touching the notification shows the relevant forum
 				Intent i = new Intent(appContext, ForumActivity.class);
@@ -511,6 +530,16 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
 		}
 	}
 
+	@Override
+	public void clearAllForumPostNotifications() {
+		androidExecutor.runOnUiThread(new Runnable() {
+			@Override
+			public void run() {
+				clearForumPostNotification();
+			}
+		});
+	}
+
 	@UiThread
 	private void showBlogPostNotification(final GroupId g) {
 		androidExecutor.runOnUiThread(new Runnable() {
@@ -522,7 +551,7 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
 				if (count == null) blogCounts.put(g, 1);
 				else blogCounts.put(g, count + 1);
 				blogTotal++;
-				updateBlogPostNotification();
+				updateBlogPostNotification(true);
 			}
 		});
 	}
@@ -535,13 +564,13 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
 				Integer count = blogCounts.remove(g);
 				if (count == null) return; // Already cleared
 				blogTotal -= count;
-				updateBlogPostNotification();
+				updateBlogPostNotification(false);
 			}
 		});
 	}
 
 	@UiThread
-	private void updateBlogPostNotification() {
+	private void updateBlogPostNotification(boolean mayAlertAgain) {
 		if (blogTotal == 0) {
 			clearBlogPostNotification();
 		} else if (settings.getBoolean(PREF_NOTIFY_BLOG, true)) {
@@ -557,7 +586,8 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
 			boolean showOnLockScreen =
 					settings.getBoolean(PREF_NOTIFY_LOCK_SCREEN, false);
 			b.setLockscreenVisibility(CATEGORY_SOCIAL, showOnLockScreen);
-			playSound(b);
+			if (mayAlertAgain) setAlertProperties(b);
+			setDeleteIntent(b, BLOG_URI);
 			// Touching the notification shows the combined blog feed
 			Intent i = new Intent(appContext, NavDrawerActivity.class);
 			i.putExtra(INTENT_BLOGS, true);
@@ -607,7 +637,8 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
 		boolean showOnLockScreen =
 				settings.getBoolean(PREF_NOTIFY_LOCK_SCREEN, false);
 		b.setLockscreenVisibility(CATEGORY_MESSAGE, showOnLockScreen);
-		playSound(b);
+		setAlertProperties(b);
+		setDeleteIntent(b, INTRODUCTION_URI);
 		// Touching the notification shows the contact list
 		Intent i = new Intent(appContext, NavDrawerActivity.class);
 		i.putExtra(INTENT_CONTACTS, true);
@@ -623,6 +654,16 @@ class AndroidNotificationManagerImpl implements AndroidNotificationManager,
 		nm.notify(INTRODUCTION_SUCCESS_NOTIFICATION_ID, b.build());
 	}
 
+	@Override
+	public void clearAllIntroductionNotifications() {
+		androidExecutor.runOnUiThread(new Runnable() {
+			@Override
+			public void run() {
+				clearIntroductionSuccessNotification();
+			}
+		});
+	}
+
 	@Override
 	public void blockNotification(final GroupId g) {
 		androidExecutor.runOnUiThread(new Runnable() {
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/NotificationCleanupService.java b/briar-android/src/main/java/org/briarproject/briar/android/NotificationCleanupService.java
new file mode 100644
index 0000000000000000000000000000000000000000..56d2161114ecb845f5d5e06ae3a20b16b765bf5d
--- /dev/null
+++ b/briar-android/src/main/java/org/briarproject/briar/android/NotificationCleanupService.java
@@ -0,0 +1,53 @@
+package org.briarproject.briar.android;
+
+import android.app.IntentService;
+import android.content.Intent;
+import android.support.annotation.Nullable;
+
+import org.briarproject.briar.api.android.AndroidNotificationManager;
+
+import javax.inject.Inject;
+
+import static org.briarproject.briar.api.android.AndroidNotificationManager.BLOG_URI;
+import static org.briarproject.briar.api.android.AndroidNotificationManager.CONTACT_URI;
+import static org.briarproject.briar.api.android.AndroidNotificationManager.FORUM_URI;
+import static org.briarproject.briar.api.android.AndroidNotificationManager.GROUP_URI;
+import static org.briarproject.briar.api.android.AndroidNotificationManager.INTRODUCTION_URI;
+
+public class NotificationCleanupService extends IntentService {
+
+	private static final String TAG =
+			NotificationCleanupService.class.getName();
+
+	@Inject
+	AndroidNotificationManager notificationManager;
+
+	public NotificationCleanupService() {
+		super(TAG);
+	}
+
+	@Override
+	public void onCreate() {
+		super.onCreate();
+		AndroidComponent applicationComponent =
+				((BriarApplication) getApplication()).getApplicationComponent();
+		applicationComponent.inject(this);
+	}
+
+	@Override
+	protected void onHandleIntent(@Nullable Intent i) {
+		if (i == null || i.getData() == null) return;
+		String uri = i.getData().toString();
+		if (uri.equals(CONTACT_URI)) {
+			notificationManager.clearAllContactNotifications();
+		} else if (uri.equals(GROUP_URI)) {
+			notificationManager.clearAllGroupMessageNotifications();
+		} else if (uri.equals(FORUM_URI)) {
+			notificationManager.clearAllForumPostNotifications();
+		} else if (uri.equals(BLOG_URI)) {
+			notificationManager.clearAllBlogPostNotifications();
+		} else if (uri.equals(INTRODUCTION_URI)) {
+			notificationManager.clearAllIntroductionNotifications();
+		}
+	}
+}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/contact/ContactListFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/contact/ContactListFragment.java
index d52915fce9e1ea38572f5935c4e0c61e689afb19..0faca234140bf3fdd8de0d2c3e036b0c3d2abefd 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/contact/ContactListFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/contact/ContactListFragment.java
@@ -179,6 +179,8 @@ public class ContactListFragment extends BaseFragment implements EventListener {
 	public void onStart() {
 		super.onStart();
 		eventBus.addListener(this);
+		notificationManager.clearAllContactNotifications();
+		notificationManager.clearAllIntroductionNotifications();
 		loadContacts();
 		list.startPeriodicUpdate();
 	}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumListFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumListFragment.java
index 4873684ccb579a10d9f23aaace5851dcbf42853f..a1d88d884541bc8a4e43454020e918586fc9a8b4 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumListFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/forum/ForumListFragment.java
@@ -119,6 +119,7 @@ public class ForumListFragment extends BaseEventFragment implements
 	@Override
 	public void onStart() {
 		super.onStart();
+		notificationManager.clearAllForumPostNotifications();
 		loadForums();
 		loadAvailableForums();
 		list.startPeriodicUpdate();
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/list/GroupListControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/list/GroupListControllerImpl.java
index 6cde4e9552a4a99320a6bc73c3a426a1f1b0bb59..cbe85631eba1c57ae514aae84b66c7ec0eda04c8 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/privategroup/list/GroupListControllerImpl.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/privategroup/list/GroupListControllerImpl.java
@@ -79,6 +79,7 @@ class GroupListControllerImpl extends DbControllerImpl
 			throw new IllegalStateException(
 					"GroupListListener needs to be attached");
 		eventBus.addListener(this);
+		notificationManager.clearAllGroupMessageNotifications();
 	}
 
 	@Override
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/util/BriarNotificationBuilder.java b/briar-android/src/main/java/org/briarproject/briar/android/util/BriarNotificationBuilder.java
index 76fab9de4b37a84f902f179d050cad377f1fed12..73c50d8dd901985d7cd49108c0c8e23300cbcfd7 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/util/BriarNotificationBuilder.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/util/BriarNotificationBuilder.java
@@ -6,7 +6,6 @@ import android.support.annotation.ColorRes;
 import android.support.v4.content.ContextCompat;
 import android.support.v7.app.NotificationCompat;
 
-import static android.support.v4.app.NotificationCompat.CATEGORY_MESSAGE;
 import static android.support.v4.app.NotificationCompat.VISIBILITY_PRIVATE;
 import static android.support.v4.app.NotificationCompat.VISIBILITY_SECRET;
 
@@ -15,6 +14,8 @@ public class BriarNotificationBuilder extends NotificationCompat.Builder {
 
 	public BriarNotificationBuilder(Context context) {
 		super(context);
+		// Auto-cancel does not fire the delete intent, see
+		// https://issuetracker.google.com/issues/36961721
 		setAutoCancel(true);
 	}
 
@@ -27,10 +28,8 @@ public class BriarNotificationBuilder extends NotificationCompat.Builder {
 			boolean show) {
 		if (Build.VERSION.SDK_INT >= 21) {
 			setCategory(category);
-			if (show)
-				setVisibility(VISIBILITY_PRIVATE);
-			else
-				setVisibility(VISIBILITY_SECRET);
+			if (show) setVisibility(VISIBILITY_PRIVATE);
+			else setVisibility(VISIBILITY_SECRET);
 		}
 		return this;
 	}
diff --git a/briar-android/src/main/java/org/briarproject/briar/api/android/AndroidNotificationManager.java b/briar-android/src/main/java/org/briarproject/briar/api/android/AndroidNotificationManager.java
index 167ee816b49a5805451577468dcab3d436b660f9..d95d258da2bc76c59708998fad708dae82158503 100644
--- a/briar-android/src/main/java/org/briarproject/briar/api/android/AndroidNotificationManager.java
+++ b/briar-android/src/main/java/org/briarproject/briar/api/android/AndroidNotificationManager.java
@@ -9,6 +9,7 @@ import org.briarproject.bramble.api.sync.GroupId;
  */
 public interface AndroidNotificationManager {
 
+	// Keys for notification preferences
 	String PREF_NOTIFY_PRIVATE = "notifyPrivateMessages";
 	String PREF_NOTIFY_GROUP = "notifyGroupMessages";
 	String PREF_NOTIFY_FORUM = "notifyForumPosts";
@@ -20,16 +21,31 @@ public interface AndroidNotificationManager {
 	String PREF_NOTIFY_VIBRATION = "notifyVibration";
 	String PREF_NOTIFY_LOCK_SCREEN = "notifyLockScreen";
 
+	// Content URIs for pending intents
+	String CONTACT_URI = "content://org.briarproject.briar/contact";
+	String GROUP_URI = "content://org.briarproject.briar/group";
+	String FORUM_URI = "content://org.briarproject.briar/forum";
+	String BLOG_URI = "content://org.briarproject.briar/blog";
+	String INTRODUCTION_URI = "content://org.briarproject.briar/introduction";
+
 	void clearContactNotification(ContactId c);
 
+	void clearAllContactNotifications();
+
 	void clearGroupMessageNotification(GroupId g);
 
+	void clearAllGroupMessageNotifications();
+
 	void clearForumPostNotification(GroupId g);
 
+	void clearAllForumPostNotifications();
+
 	void clearBlogPostNotification(GroupId g);
 
 	void clearAllBlogPostNotifications();
 
+	void clearAllIntroductionNotifications();
+
 	void blockContactNotification(ContactId c);
 
 	void unblockContactNotification(ContactId c);