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 817bdd0e4e541c2a11851de0008acb7f28a85b5c..9923043643e8983be4adc12d72877df2e5337b7b 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
@@ -28,6 +28,7 @@ import org.briarproject.briar.BriarCoreModule;
 import org.briarproject.briar.android.reporting.BriarReportSender;
 import org.briarproject.briar.api.android.AndroidNotificationManager;
 import org.briarproject.briar.api.android.ReferenceManager;
+import org.briarproject.briar.api.android.ScreenFilterMonitor;
 import org.briarproject.briar.api.blog.BlogManager;
 import org.briarproject.briar.api.blog.BlogPostFactory;
 import org.briarproject.briar.api.blog.BlogSharingManager;
@@ -89,6 +90,8 @@ public interface AndroidComponent
 
 	AndroidNotificationManager androidNotificationManager();
 
+	ScreenFilterMonitor screenFilterMonitor();
+
 	ConnectionRegistry connectionRegistry();
 
 	ContactManager contactManager();
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java b/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java
index 667b4ee2919447712ae626d9184d86ffcc90b8eb..479b3e94ca6d6bd3ce8fa8e6db9312eb86aa9f62 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/AppModule.java
@@ -16,6 +16,7 @@ import org.briarproject.bramble.api.ui.UiCallback;
 import org.briarproject.bramble.util.StringUtils;
 import org.briarproject.briar.api.android.AndroidNotificationManager;
 import org.briarproject.briar.api.android.ReferenceManager;
+import org.briarproject.briar.api.android.ScreenFilterMonitor;
 
 import java.io.File;
 import java.security.GeneralSecurityException;
@@ -37,6 +38,8 @@ public class AppModule {
 	static class EagerSingletons {
 		@Inject
 		AndroidNotificationManager androidNotificationManager;
+		@Inject
+		ScreenFilterMonitor screenFilterMonitor;
 	}
 
 	private final Application application;
@@ -166,4 +169,12 @@ public class AppModule {
 		eventBus.addListener(notificationManager);
 		return notificationManager;
 	}
+
+	@Provides
+	@Singleton
+	ScreenFilterMonitor provideScreenFilterMonitor(
+			LifecycleManager lifecycleManager, ScreenFilterMonitorImpl sfm) {
+		lifecycleManager.registerService(sfm);
+		return sfm;
+	}
 }
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/ScreenFilterMonitorImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/ScreenFilterMonitorImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..cb195108af4f941db686df4c512cb05cd6601b31
--- /dev/null
+++ b/briar-android/src/main/java/org/briarproject/briar/android/ScreenFilterMonitorImpl.java
@@ -0,0 +1,232 @@
+package org.briarproject.briar.android;
+
+import android.app.Application;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.UiThread;
+import android.support.v7.preference.PreferenceManager;
+
+import org.briarproject.bramble.api.lifecycle.Service;
+import org.briarproject.bramble.api.lifecycle.ServiceException;
+import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
+import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
+import org.briarproject.bramble.api.system.AndroidExecutor;
+import org.briarproject.briar.api.android.ScreenFilterMonitor;
+
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.inject.Inject;
+
+import static android.Manifest.permission.SYSTEM_ALERT_WINDOW;
+
+@MethodsNotNullByDefault
+@ParametersNotNullByDefault
+public class ScreenFilterMonitorImpl extends BroadcastReceiver
+		implements Service,
+		ScreenFilterMonitor {
+
+	private static final Logger LOG =
+			Logger.getLogger(ScreenFilterMonitorImpl.class.getName());
+	private static final String PREF_SCREEN_FILTER_APPS =
+			"shownScreenFilterApps";
+	private final Context appContext;
+	private final AndroidExecutor androidExecutor;
+	private final LinkedList<String> appNames = new LinkedList<>();
+	private final PackageManager pm;
+	private final SharedPreferences prefs;
+	private final AtomicBoolean used = new AtomicBoolean(false);
+	private final Set<String> apps = new HashSet<>();
+	private final Set<String> shownApps;
+	// Used solely for the UiThread
+	private boolean serviceStarted = false;
+
+	@Inject
+	ScreenFilterMonitorImpl(AndroidExecutor executor, Application app) {
+		this.androidExecutor = executor;
+		this.appContext = app;
+		pm = appContext.getPackageManager();
+		prefs = PreferenceManager.getDefaultSharedPreferences(appContext);
+		shownApps = getShownScreenFilterApps();
+	}
+
+	@Override
+	public void startService() throws ServiceException {
+		if (used.getAndSet(true)) throw new IllegalStateException();
+		Future<Void> f = androidExecutor.runOnUiThread(new Callable<Void>() {
+			@Override
+			public Void call() {
+				IntentFilter intentFilter = new IntentFilter();
+				intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED);
+				intentFilter.addDataScheme("package");
+				appContext.registerReceiver(ScreenFilterMonitorImpl.this,
+						intentFilter);
+				apps.addAll(getInstalledScreenFilterApps());
+				serviceStarted = true;
+				return null;
+			}
+		});
+		try {
+			f.get();
+		} catch (InterruptedException | ExecutionException e) {
+			throw new ServiceException(e);
+		}
+	}
+
+	@Override
+	public void stopService() throws ServiceException {
+		Future<Void> f = androidExecutor.runOnUiThread(new Callable<Void>() {
+			@Override
+			public Void call() {
+				serviceStarted = false;
+				appContext.unregisterReceiver(ScreenFilterMonitorImpl.this);
+				return null;
+			}
+		});
+		try {
+			f.get();
+		} catch (InterruptedException | ExecutionException e) {
+			throw new ServiceException(e);
+		}
+	}
+
+	private Set<String> getShownScreenFilterApps() {
+		// res must not be modified
+		Set<String> s =
+				prefs.getStringSet(PREF_SCREEN_FILTER_APPS, null);
+		HashSet<String> result = new HashSet<>();
+		if (s != null) {
+			result.addAll(s);
+		}
+		return result;
+	}
+
+	@Override
+	public void onReceive(Context context, Intent intent) {
+		if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+			final String packageName =
+					intent.getData().getEncodedSchemeSpecificPart();
+			androidExecutor.runOnUiThread(new Runnable() {
+				@Override
+				public void run() {
+					String pkg = isOverlayApp(packageName);
+					if (pkg == null) {
+						return;
+					}
+					apps.add(pkg);
+				}
+			});
+		}
+	}
+
+	@Override
+	@UiThread
+	public Set<String> getApps() {
+		if (!serviceStarted) {
+			apps.addAll(getInstalledScreenFilterApps());
+		}
+		TreeSet<String> buf = new TreeSet<>();
+		if (apps.isEmpty()) {
+			return buf;
+		}
+		buf.addAll(apps);
+		buf.removeAll(shownApps);
+		return buf;
+	}
+
+	@Override
+	@UiThread
+	public void storeAppsAsShown(Collection<String> s, boolean persistent) {
+		HashSet<String> buf = new HashSet(s);
+		shownApps.addAll(buf);
+		if (persistent && !s.isEmpty()) {
+			buf.addAll(getShownScreenFilterApps());
+			prefs.edit()
+					.putStringSet(PREF_SCREEN_FILTER_APPS, buf)
+					.apply();
+		}
+	}
+
+	private Set<String> getInstalledScreenFilterApps() {
+		HashSet<String> screenFilterApps = new HashSet<>();
+		List<PackageInfo> packageInfos =
+				pm.getInstalledPackages(PackageManager.GET_PERMISSIONS);
+		for (PackageInfo packageInfo : packageInfos) {
+			if (isOverlayApp(packageInfo)) {
+				String name = pkgToString(packageInfo);
+				if (name != null) {
+					screenFilterApps.add(name);
+				}
+			}
+		}
+		return screenFilterApps;
+	}
+
+	// Checks if pkg uses the SYSTEM_ALERT_WINDOW permission and if so
+	// returns the app name.
+	@Nullable
+	private String isOverlayApp(String pkg) {
+		try {
+			PackageInfo pkgInfo =
+					pm.getPackageInfo(pkg, PackageManager.GET_PERMISSIONS);
+			if (isOverlayApp(pkgInfo)) {
+				return pkgToString(pkgInfo);
+			}
+		} catch (PackageManager.NameNotFoundException ignored) {
+			if (LOG.isLoggable(Level.WARNING)) {
+				LOG.warning("Package name not found: " + pkg);
+			}
+		}
+		return null;
+	}
+
+	// Fetch the application name for a given package.
+	@Nullable
+	private String pkgToString(PackageInfo pkgInfo) {
+		CharSequence seq = pm.getApplicationLabel(pkgInfo.applicationInfo);
+		if (seq != null) {
+			return seq.toString();
+		}
+		return null;
+	}
+
+	// Checks if an installed pkg is a user app using the permission.
+	private boolean isOverlayApp(PackageInfo packageInfo) {
+		int mask = ApplicationInfo.FLAG_SYSTEM |
+				ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+		// Ignore system apps
+		if ((packageInfo.applicationInfo.flags & mask) != 0) {
+			return false;
+		}
+		//Get Permissions
+		String[] requestedPermissions =
+				packageInfo.requestedPermissions;
+		if (requestedPermissions != null) {
+			for (String requestedPermission : requestedPermissions) {
+				if (requestedPermission
+						.equals(SYSTEM_ALERT_WINDOW)) {
+					return true;
+				}
+			}
+		}
+		return false;
+	}
+}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/BaseActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/BaseActivity.java
index 7c7b62c63c4cb0f969b8431f5665d0eb88587971..8b12f7e2b15cb7f6f4cc35bb7b0f923079b65bbc 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/activity/BaseActivity.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/BaseActivity.java
@@ -13,11 +13,15 @@ import org.briarproject.briar.android.BriarApplication;
 import org.briarproject.briar.android.DestroyableContext;
 import org.briarproject.briar.android.controller.ActivityLifecycleController;
 import org.briarproject.briar.android.forum.ForumModule;
+import org.briarproject.briar.android.fragment.SFDialogFragment;
+import org.briarproject.briar.api.android.ScreenFilterMonitor;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Set;
 
 import javax.annotation.Nullable;
+import javax.inject.Inject;
 
 import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
 import static android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT;
@@ -25,13 +29,16 @@ import static org.briarproject.briar.android.TestingConstants.PREVENT_SCREENSHOT
 
 public abstract class BaseActivity extends AppCompatActivity
 		implements DestroyableContext {
-
 	protected ActivityComponent activityComponent;
 
 	private final List<ActivityLifecycleController> lifecycleControllers =
 			new ArrayList<>();
 	private boolean destroyed = false;
 
+	@Inject
+	protected ScreenFilterMonitor screenFilterMonitor;
+	private SFDialogFragment dialogFrag;
+
 	public abstract void injectActivity(ActivityComponent component);
 
 	public void addLifecycleController(ActivityLifecycleController alc) {
@@ -58,6 +65,7 @@ public abstract class BaseActivity extends AppCompatActivity
 		for (ActivityLifecycleController alc : lifecycleControllers) {
 			alc.onActivityCreate(this);
 		}
+
 	}
 
 	public ActivityComponent getActivityComponent() {
@@ -89,6 +97,35 @@ public abstract class BaseActivity extends AppCompatActivity
 		}
 	}
 
+	@Override
+	protected void onPostResume() {
+		super.onPostResume();
+		showNewScreenFilterWarning();
+	}
+
+	@Override
+	protected void onPause() {
+		super.onPause();
+		if (dialogFrag != null) {
+			dialogFrag.dismiss();
+			dialogFrag = null;
+		}
+	}
+
+	protected void showNewScreenFilterWarning() {
+		final Set<String> apps = screenFilterMonitor.getApps();
+		if (apps.isEmpty()) {
+			return;
+		}
+		dialogFrag = SFDialogFragment.newInstance(new ArrayList<>(apps));
+		dialogFrag.setCancelable(false);
+		dialogFrag.show(getSupportFragmentManager(), "SFDialog");
+	}
+
+	public void rememberShownApps(ArrayList<String> s, boolean permanent) {
+		screenFilterMonitor.storeAppsAsShown(s, permanent);
+	}
+
 	@Override
 	protected void onDestroy() {
 		super.onDestroy();
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/fragment/SFDialogFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/fragment/SFDialogFragment.java
new file mode 100644
index 0000000000000000000000000000000000000000..e20e814d685b249b2694aec1d85bf1ae6f33aa01
--- /dev/null
+++ b/briar-android/src/main/java/org/briarproject/briar/android/fragment/SFDialogFragment.java
@@ -0,0 +1,66 @@
+package org.briarproject.briar.android.fragment;
+
+import android.app.Dialog;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v4.app.DialogFragment;
+import android.support.v7.app.AlertDialog;
+import android.text.TextUtils;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.TextView;
+
+import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
+import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
+import org.briarproject.briar.R;
+import org.briarproject.briar.android.activity.BaseActivity;
+
+import java.util.ArrayList;
+
+@MethodsNotNullByDefault
+@ParametersNotNullByDefault
+public class SFDialogFragment extends DialogFragment {
+
+	public static SFDialogFragment newInstance(ArrayList<String> apps) {
+		SFDialogFragment frag = new SFDialogFragment();
+		Bundle args = new Bundle();
+		args.putStringArrayList("apps", apps);
+		frag.setArguments(args);
+		return frag;
+	}
+
+	@Override
+	public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
+		AlertDialog.Builder builder =
+				new AlertDialog.Builder(
+						getActivity(),
+						R.style.BriarDialogThemeNoFilter);
+		builder.setTitle(R.string.screen_filter_title);
+		LayoutInflater li = getActivity().getLayoutInflater();
+		//Pass null here because it's an AlertDialog
+		View v =
+				li.inflate(R.layout.alert_dialog_checkbox, null,
+						false);
+		TextView t = (TextView) v.findViewById(R.id.alert_dialog_text);
+		final ArrayList<String> apps =
+				getArguments().getStringArrayList("apps");
+		t.setText(getString(R.string.screen_filter_body, TextUtils
+				.join("\n", apps)));
+		final CheckBox cb =
+				(CheckBox) v.findViewById(
+						R.id.checkBox_screen_filter_reminder);
+		builder.setNeutralButton(R.string.continue_button,
+				new DialogInterface.OnClickListener() {
+					@Override
+					public void onClick(DialogInterface dialog,
+							int which) {
+						((BaseActivity) getActivity())
+								.rememberShownApps(apps, cb.isChecked());
+					}
+				});
+		builder.setView(v);
+		return builder.create();
+	}
+}
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/splash/SplashScreenActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/splash/SplashScreenActivity.java
index 283ea0feb6b54b1cbd4591d9cb8ab0331ba58921..21c2e0ede23e1f35689df3a9d6e837d48c87e975 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/splash/SplashScreenActivity.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/splash/SplashScreenActivity.java
@@ -83,6 +83,10 @@ public class SplashScreenActivity extends BaseActivity {
 		}
 	}
 
+	@Override
+	protected void showNewScreenFilterWarning() {
+	}
+
 	private void enableStrictMode() {
 		if (TESTING) {
 			ThreadPolicy.Builder threadPolicy = new ThreadPolicy.Builder();
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java b/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java
index 7d2e898eb0ad187481bb9dfd70595fd15cde82ee..d6346fffe29ffc013f23d37d92d4f0e06b604cdf 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/util/UiUtils.java
@@ -120,5 +120,5 @@ public class UiUtils {
 	public static String getBulbTransitionName(ContactId c) {
 		return "bulb" + c.getInt();
 	}
-
+	
 }
diff --git a/briar-android/src/main/java/org/briarproject/briar/api/android/ScreenFilterMonitor.java b/briar-android/src/main/java/org/briarproject/briar/api/android/ScreenFilterMonitor.java
new file mode 100644
index 0000000000000000000000000000000000000000..b596ecbb2ad3c2ff310cd766b5472430209d60fb
--- /dev/null
+++ b/briar-android/src/main/java/org/briarproject/briar/api/android/ScreenFilterMonitor.java
@@ -0,0 +1,15 @@
+package org.briarproject.briar.api.android;
+
+import android.support.annotation.UiThread;
+
+import java.util.Collection;
+import java.util.Set;
+
+public interface ScreenFilterMonitor {
+
+	@UiThread
+	Set<String> getApps();
+
+	@UiThread
+	void storeAppsAsShown(Collection<String> s, boolean persistent);
+}
diff --git a/briar-android/src/main/res/layout/alert_dialog_checkbox.xml b/briar-android/src/main/res/layout/alert_dialog_checkbox.xml
new file mode 100644
index 0000000000000000000000000000000000000000..718589da9a6be8aca0a35609fd29c591bf5634de
--- /dev/null
+++ b/briar-android/src/main/res/layout/alert_dialog_checkbox.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:filterTouchesWhenObscured="false"
+              android:orientation="vertical">
+
+	<ScrollView
+		android:layout_width="match_parent"
+		android:layout_height="wrap_content"
+		android:layout_weight="1"
+		android:fadeScrollbars="false"
+		android:paddingLeft="20dp"
+		android:paddingRight="20dp"
+		android:paddingStart="20dp"
+		android:paddingTop="20dp"
+		android:theme="@style/BriarTheme">
+
+		<TextView
+			android:id="@+id/alert_dialog_text"
+			android:layout_width="match_parent"
+			android:layout_height="wrap_content"
+			android:paddingLeft="3dp"
+			android:paddingRight="6dp"
+			android:text="TextView"
+			android:textAppearance="@style/BriarTextBody"
+			android:theme="@+theme/BriarDialogTheme"/>
+	</ScrollView>
+
+	<CheckBox
+		android:id="@+id/checkBox_screen_filter_reminder"
+		android:layout_width="match_parent"
+		android:layout_height="wrap_content"
+		android:layout_marginLeft="15dp"
+		android:layout_marginStart="15dp"
+		android:layout_weight="0"
+		android:filterTouchesWhenObscured="false"
+		android:text="@string/checkbox_dont_show_again"
+		android:textAppearance="@style/BriarTextBody"/>
+</LinearLayout>
diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml
index 4cdd0efb7cdc674d57c63bb7551776c40c083390..a10f34cafa8da8473417623149a8e0cfa33d8a94 100644
--- a/briar-android/src/main/res/values/strings.xml
+++ b/briar-android/src/main/res/values/strings.xml
@@ -380,4 +380,10 @@
 	<!-- Sign Out -->
 	<string name="progress_title_logout">Signing out of Briar…</string>
 
+	<!-- Screen Filters & Tapjacking -->
+	<string name="screen_filter_title">Screen filter detected</string>
+	<string name="screen_filter_body">The following apps have permission to draw over other apps:\n\n%1$s \n\nBriar will not respond to touches when another app is drawing over it.
+If you experience any problems, try turning off these apps when using Briar.\n</string>
+	<string name="checkbox_dont_show_again">Don\'t warn me again for these apps</string>
+
 </resources>
diff --git a/briar-android/src/main/res/values/themes.xml b/briar-android/src/main/res/values/themes.xml
index 1676cf7dfcd1d0e28ecc400893727e1c322ef132..db57d78d40b380d4177193210e72b52abfb71f3c 100644
--- a/briar-android/src/main/res/values/themes.xml
+++ b/briar-android/src/main/res/values/themes.xml
@@ -14,6 +14,7 @@
 		<item name="android:textColorTertiaryInverse">@color/briar_text_tertiary_inverse</item>
 		<item name="android:textColorLink">@color/briar_text_link</item>
 		<item name="android:windowAnimationStyle">@style/ActivityAnimation</item>
+		<item name="android:filterTouchesWhenObscured">true</item>
 
 		<!-- These fix a long-standing UI bug in the support preference library -->
 		<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
@@ -47,6 +48,12 @@
 		<item name="android:textColorTertiaryInverse">@color/briar_text_tertiary_inverse</item>
 		<item name="android:textColorLink">@color/briar_text_link</item>
 		<item name="android:windowAnimationStyle">@style/DialogAnimation</item>
+		<item name="android:filterTouchesWhenObscured">true</item>
+	</style>
+
+	<!-- Use this with care. Only used for the screen filter warning dialog -->
+	<style name="BriarDialogThemeNoFilter" parent="BriarDialogTheme">
+		<item name="android:filterTouchesWhenObscured">false</item>
 	</style>
 
 	<style name="DialogAnimation" parent="@android:style/Animation.Dialog">