From 753068288f6d6a76d5d709dff2855e745ad5899f Mon Sep 17 00:00:00 2001
From: akwizgran <michael@briarproject.org>
Date: Thu, 4 Jan 2018 13:19:49 +0000
Subject: [PATCH] Allow filtered taps if all overlay apps are whitelisted.

---
 .../briar/android/AndroidComponent.java       |  4 +
 .../briarproject/briar/android/AppModule.java |  6 ++
 .../android/ScreenFilterMonitorImpl.java      | 78 +++++++++++++------
 .../android/activity/ActivityComponent.java   |  4 +
 .../android/activity/ActivityModule.java      |  8 --
 .../briar/android/activity/BaseActivity.java  | 27 ++++---
 .../fragment/ScreenFilterDialogFragment.java  | 66 +++++++++++++---
 .../android/widget/TapSafeFrameLayout.java    |  8 +-
 .../api/android/ScreenFilterMonitor.java      | 31 +++++++-
 .../main/res/layout/dialog_screen_filter.xml  | 26 +++++++
 briar-android/src/main/res/values/strings.xml |  1 +
 11 files changed, 200 insertions(+), 59 deletions(-)
 create mode 100644 briar-android/src/main/res/layout/dialog_screen_filter.xml

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 1c6cc9d86f..02a5dc0ff7 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
@@ -1,5 +1,7 @@
 package org.briarproject.briar.android;
 
+import android.content.SharedPreferences;
+
 import org.briarproject.bramble.BrambleAndroidModule;
 import org.briarproject.bramble.BrambleCoreEagerSingletons;
 import org.briarproject.bramble.BrambleCoreModule;
@@ -89,6 +91,8 @@ public interface AndroidComponent
 
 	AndroidNotificationManager androidNotificationManager();
 
+	SharedPreferences sharedPreferences();
+
 	ScreenFilterMonitor screenFilterMonitor();
 
 	ConnectionRegistry connectionRegistry();
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 c0e0689765..947d860762 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
@@ -1,6 +1,7 @@
 package org.briarproject.briar.android;
 
 import android.app.Application;
+import android.content.SharedPreferences;
 
 import org.briarproject.bramble.api.crypto.CryptoComponent;
 import org.briarproject.bramble.api.crypto.PublicKey;
@@ -157,6 +158,11 @@ public class AppModule {
 		return devConfig;
 	}
 
+	@Provides
+	SharedPreferences provideSharedPreferences(Application app) {
+		return app.getSharedPreferences("db", MODE_PRIVATE);
+	}
+
 	@Provides
 	@Singleton
 	ReferenceManager provideReferenceManager() {
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
index e1a88b5928..d9c5ac65ea 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/ScreenFilterMonitorImpl.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/ScreenFilterMonitorImpl.java
@@ -1,6 +1,8 @@
 package org.briarproject.briar.android;
 
+import android.annotation.SuppressLint;
 import android.app.Application;
+import android.content.SharedPreferences;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -16,19 +18,23 @@ import java.io.InputStream;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
-import java.util.TreeSet;
 import java.util.logging.Logger;
 
-import javax.annotation.Nullable;
 import javax.inject.Inject;
 
 import static android.Manifest.permission.SYSTEM_ALERT_WINDOW;
 import static android.content.pm.ApplicationInfo.FLAG_SYSTEM;
 import static android.content.pm.ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
+import static android.content.pm.PackageInfo.REQUESTED_PERMISSION_GRANTED;
 import static android.content.pm.PackageManager.GET_PERMISSIONS;
 import static android.content.pm.PackageManager.GET_SIGNATURES;
+import static android.os.Build.VERSION.SDK_INT;
 import static java.util.logging.Level.WARNING;
 
 @NotNullByDefault
@@ -56,54 +62,75 @@ class ScreenFilterMonitorImpl implements ScreenFilterMonitor {
 					"82BA35E003C1B4B10DD244A8EE24FFFD333872AB5221985EDAB0FC0D" +
 					"0B145B6AA192858E79020103";
 
+	private static final String PREF_KEY_ALLOWED = "allowedOverlayApps";
+
 	private final PackageManager pm;
+	private final SharedPreferences prefs;
 
 	@Inject
-	ScreenFilterMonitorImpl(Application app) {
+	ScreenFilterMonitorImpl(Application app, SharedPreferences prefs) {
 		pm = app.getPackageManager();
+		this.prefs = prefs;
 	}
 
 	@Override
 	@UiThread
-	public Set<String> getApps() {
-		Set<String> screenFilterApps = new TreeSet<>();
+	public Collection<AppDetails> getApps() {
+		Set<String> allowed = prefs.getStringSet(PREF_KEY_ALLOWED,
+				Collections.emptySet());
+		List<AppDetails> apps = new ArrayList<>();
 		List<PackageInfo> packageInfos =
 				pm.getInstalledPackages(GET_PERMISSIONS);
 		for (PackageInfo packageInfo : packageInfos) {
-			if (isOverlayApp(packageInfo)) {
-				String name = pkgToString(packageInfo);
-				if (name != null) {
-					screenFilterApps.add(name);
-				}
+			if (!allowed.contains(packageInfo.packageName)
+					&& isOverlayApp(packageInfo)) {
+				String name = getAppName(packageInfo);
+				apps.add(new AppDetails(name, packageInfo.packageName));
 			}
 		}
-		return screenFilterApps;
+		Collections.sort(apps, (a, b) -> a.name.compareTo(b.name));
+		return apps;
 	}
 
-	// Fetches the application name for a given package.
-	@Nullable
-	private String pkgToString(PackageInfo pkgInfo) {
+	@Override
+	public void allowApps(Collection<String> packageNames) {
+		Set<String> allowed = prefs.getStringSet(PREF_KEY_ALLOWED,
+				Collections.emptySet());
+		Set<String> merged = new HashSet<>(allowed);
+		merged.addAll(packageNames);
+		prefs.edit().putStringSet(PREF_KEY_ALLOWED, merged).apply();
+	}
+
+	// Returns the application name for a given package, or the package name
+	// if no application name is available
+	private String getAppName(PackageInfo pkgInfo) {
 		CharSequence seq = pm.getApplicationLabel(pkgInfo.applicationInfo);
-		if (seq != null) {
-			return seq.toString();
-		}
-		return null;
+		return seq == null ? pkgInfo.packageName : seq.toString();
 	}
 
 	// Checks if an installed package is a user app using the permission.
 	private boolean isOverlayApp(PackageInfo packageInfo) {
 		int mask = FLAG_SYSTEM | FLAG_UPDATED_SYSTEM_APP;
 		// Ignore system apps
-		if ((packageInfo.applicationInfo.flags & mask) != 0) {
-			return false;
-		}
+		if ((packageInfo.applicationInfo.flags & mask) != 0) return false;
 		// Ignore Play Services, it's effectively a system app
-		if (isPlayServices(packageInfo.packageName)) {
-			return false;
-		}
+		if (isPlayServices(packageInfo.packageName)) return false;
 		// Get permissions
 		String[] requestedPermissions = packageInfo.requestedPermissions;
-		if (requestedPermissions != null) {
+		if (requestedPermissions == null) return false;
+		if (SDK_INT >= 16 && SDK_INT < 23) {
+			// Check whether the permission has been requested and granted
+			int[] flags = packageInfo.requestedPermissionsFlags;
+			if (flags == null || flags.length != requestedPermissions.length)
+				throw new AssertionError();
+			for (int i = 0; i < requestedPermissions.length; i++) {
+				if (requestedPermissions[i].equals(SYSTEM_ALERT_WINDOW)
+						&& (flags[i] & REQUESTED_PERMISSION_GRANTED) != 0) {
+					return true;
+				}
+			}
+		} else {
+			// Check whether the permission has been requested
 			for (String requestedPermission : requestedPermissions) {
 				if (requestedPermission.equals(SYSTEM_ALERT_WINDOW)) {
 					return true;
@@ -113,6 +140,7 @@ class ScreenFilterMonitorImpl implements ScreenFilterMonitor {
 		return false;
 	}
 
+	@SuppressLint("PackageManagerGetSignatures")
 	private boolean isPlayServices(String pkg) {
 		if (!PLAY_SERVICES_PACKAGE.equals(pkg)) return false;
 		try {
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java
index f02774ae51..4066c384a7 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityComponent.java
@@ -21,6 +21,7 @@ import org.briarproject.briar.android.forum.CreateForumActivity;
 import org.briarproject.briar.android.forum.ForumActivity;
 import org.briarproject.briar.android.forum.ForumListFragment;
 import org.briarproject.briar.android.forum.ForumModule;
+import org.briarproject.briar.android.fragment.ScreenFilterDialogFragment;
 import org.briarproject.briar.android.introduction.ContactChooserFragment;
 import org.briarproject.briar.android.introduction.IntroductionActivity;
 import org.briarproject.briar.android.introduction.IntroductionMessageFragment;
@@ -152,7 +153,9 @@ public interface ActivityComponent {
 
 	// Fragments
 	void inject(AuthorNameFragment fragment);
+
 	void inject(PasswordFragment fragment);
+
 	void inject(DozeFragment fragment);
 
 	void inject(ContactListFragment fragment);
@@ -189,4 +192,5 @@ public interface ActivityComponent {
 
 	void inject(SettingsFragment fragment);
 
+	void inject(ScreenFilterDialogFragment fragment);
 }
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityModule.java b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityModule.java
index 2a00be5ccf..2651833f19 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityModule.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/activity/ActivityModule.java
@@ -1,7 +1,6 @@
 package org.briarproject.briar.android.activity;
 
 import android.app.Activity;
-import android.content.SharedPreferences;
 
 import org.briarproject.briar.android.controller.BriarController;
 import org.briarproject.briar.android.controller.BriarControllerImpl;
@@ -19,7 +18,6 @@ import org.briarproject.briar.android.navdrawer.NavDrawerControllerImpl;
 import dagger.Module;
 import dagger.Provides;
 
-import static android.content.Context.MODE_PRIVATE;
 import static org.briarproject.briar.android.BriarService.BriarServiceConnection;
 
 @Module
@@ -57,12 +55,6 @@ public class ActivityModule {
 		return configController;
 	}
 
-	@ActivityScope
-	@Provides
-	SharedPreferences provideSharedPreferences(Activity activity) {
-		return activity.getSharedPreferences("db", MODE_PRIVATE);
-	}
-
 	@ActivityScope
 	@Provides
 	PasswordController providePasswordController(
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 88e6302ecb..59e0cca707 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
@@ -24,10 +24,11 @@ import org.briarproject.briar.android.fragment.ScreenFilterDialogFragment;
 import org.briarproject.briar.android.widget.TapSafeFrameLayout;
 import org.briarproject.briar.android.widget.TapSafeFrameLayout.OnTapFilteredListener;
 import org.briarproject.briar.api.android.ScreenFilterMonitor;
+import org.briarproject.briar.api.android.ScreenFilterMonitor.AppDetails;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.List;
-import java.util.Set;
 
 import javax.annotation.Nullable;
 import javax.inject.Inject;
@@ -132,16 +133,19 @@ public abstract class BaseActivity extends AppCompatActivity
 				.commit();
 	}
 
-	private void showScreenFilterWarning() {
-		if (dialogFrag != null && dialogFrag.isVisible()) return;
-		Set<String> apps = screenFilterMonitor.getApps();
-		if (apps.isEmpty()) return;
-		dialogFrag =
-				ScreenFilterDialogFragment.newInstance(new ArrayList<>(apps));
+	private boolean showScreenFilterWarning() {
+		// If the dialog is already visible, filter the tap
+		if (dialogFrag != null && dialogFrag.isVisible()) return false;
+		Collection<AppDetails> apps = screenFilterMonitor.getApps();
+		// If all overlay apps are allowed or system apps, allow the tap
+		if (apps.isEmpty()) return true;
+		dialogFrag = ScreenFilterDialogFragment.newInstance(apps);
 		dialogFrag.setCancelable(false);
 		// Show dialog unless onSaveInstanceState() has been called, see #1112
 		FragmentManager fm = getSupportFragmentManager();
 		if (!fm.isStateSaved()) dialogFrag.show(fm, dialogFrag.getTag());
+		// Filter the tap
+		return false;
 	}
 
 	@Override
@@ -198,7 +202,10 @@ public abstract class BaseActivity extends AppCompatActivity
 		View decorView = getWindow().getDecorView();
 		if (decorView instanceof ViewGroup) {
 			Toolbar toolbar = findToolbar((ViewGroup) decorView);
-			if (toolbar != null) toolbar.setFilterTouchesWhenObscured(true);
+			if (toolbar != null) {
+				boolean filter = !screenFilterMonitor.getApps().isEmpty();
+				toolbar.setFilterTouchesWhenObscured(filter);
+			}
 		}
 	}
 
@@ -239,7 +246,7 @@ public abstract class BaseActivity extends AppCompatActivity
 	}
 
 	@Override
-	public void onTapFiltered() {
-		showScreenFilterWarning();
+	public boolean shouldAllowTap() {
+		return showScreenFilterWarning();
 	}
 }
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/fragment/ScreenFilterDialogFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/fragment/ScreenFilterDialogFragment.java
index b1e644e96a..037438b50d 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/fragment/ScreenFilterDialogFragment.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/fragment/ScreenFilterDialogFragment.java
@@ -1,40 +1,86 @@
 package org.briarproject.briar.android.fragment;
 
+import android.annotation.SuppressLint;
+import android.app.Activity;
 import android.app.Dialog;
 import android.os.Bundle;
 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.NotNullByDefault;
+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 org.briarproject.briar.api.android.ScreenFilterMonitor;
+import org.briarproject.briar.api.android.ScreenFilterMonitor.AppDetails;
 
 import java.util.ArrayList;
+import java.util.Collection;
 
 import javax.annotation.Nullable;
+import javax.inject.Inject;
 
-@NotNullByDefault
+@MethodsNotNullByDefault
+@ParametersNotNullByDefault
 public class ScreenFilterDialogFragment extends DialogFragment {
 
+	@Inject
+	ScreenFilterMonitor screenFilterMonitor;
+
 	public static ScreenFilterDialogFragment newInstance(
-			ArrayList<String> apps) {
+			Collection<AppDetails> apps) {
 		ScreenFilterDialogFragment frag = new ScreenFilterDialogFragment();
 		Bundle args = new Bundle();
-		args.putStringArrayList("apps", apps);
+		ArrayList<String> appNames = new ArrayList<>();
+		for (AppDetails a : apps) appNames.add(a.name);
+		args.putStringArrayList("appNames", appNames);
+		ArrayList<String> packageNames = new ArrayList<>();
+		for (AppDetails a : apps) packageNames.add(a.packageName);
+		args.putStringArrayList("packageNames", packageNames);
 		frag.setArguments(args);
 		return frag;
 	}
 
+	@Override
+	public void onActivityCreated(@Nullable Bundle savedInstanceState) {
+		super.onActivityCreated(savedInstanceState);
+		Activity activity = getActivity();
+		if (activity == null) throw new IllegalStateException();
+		((BaseActivity) activity).getActivityComponent().inject(this);
+	}
+
 	@Override
 	public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
-		AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(),
+		Activity activity = getActivity();
+		if (activity == null) throw new IllegalStateException();
+		AlertDialog.Builder builder = new AlertDialog.Builder(activity,
 				R.style.BriarDialogThemeNoFilter);
 		builder.setTitle(R.string.screen_filter_title);
-		ArrayList<String> apps = getArguments().getStringArrayList("apps");
-		builder.setMessage(getString(R.string.screen_filter_body,
-				TextUtils.join("\n", apps)));
-		builder.setNeutralButton(R.string.continue_button,
-				(dialog, which) -> dialog.dismiss());
+		Bundle args = getArguments();
+		if (args == null) throw new IllegalStateException();
+		ArrayList<String> appNames = args.getStringArrayList("appNames");
+		ArrayList<String> packageNames =
+				args.getStringArrayList("packageNames");
+		if (appNames == null || packageNames == null)
+			throw new IllegalStateException();
+		LayoutInflater inflater = activity.getLayoutInflater();
+		// See https://stackoverflow.com/a/24720976/6314875
+		@SuppressLint("InflateParams")
+		View dialogView = inflater.inflate(R.layout.dialog_screen_filter, null);
+		builder.setView(dialogView);
+		TextView message = dialogView.findViewById(R.id.screen_filter_message);
+		message.setText(getString(R.string.screen_filter_body,
+				TextUtils.join("\n", appNames)));
+		CheckBox allow = dialogView.findViewById(R.id.screen_filter_checkbox);
+		builder.setNeutralButton(R.string.continue_button, (dialog, which) -> {
+			if (allow.isChecked()) screenFilterMonitor.allowApps(packageNames);
+			dialog.dismiss();
+		});
 		return builder.create();
 	}
 }
diff --git a/briar-android/src/main/java/org/briarproject/briar/android/widget/TapSafeFrameLayout.java b/briar-android/src/main/java/org/briarproject/briar/android/widget/TapSafeFrameLayout.java
index 840e68b085..701406e1fa 100644
--- a/briar-android/src/main/java/org/briarproject/briar/android/widget/TapSafeFrameLayout.java
+++ b/briar-android/src/main/java/org/briarproject/briar/android/widget/TapSafeFrameLayout.java
@@ -40,12 +40,12 @@ public class TapSafeFrameLayout extends FrameLayout {
 
 	@Override
 	public boolean onFilterTouchEventForSecurity(MotionEvent e) {
-		boolean filter = (e.getFlags() & FLAG_WINDOW_IS_OBSCURED) != 0;
-		if (filter && listener != null) listener.onTapFiltered();
-		return !filter;
+		boolean obscured = (e.getFlags() & FLAG_WINDOW_IS_OBSCURED) != 0;
+		if (obscured && listener != null) return listener.shouldAllowTap();
+		else return !obscured;
 	}
 
 	public interface OnTapFilteredListener {
-		void onTapFiltered();
+		boolean shouldAllowTap();
 	}
 }
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
index 9df5add2f7..a14b3b078b 100644
--- 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
@@ -2,10 +2,37 @@ package org.briarproject.briar.api.android;
 
 import android.support.annotation.UiThread;
 
-import java.util.Set;
+import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
 
+import java.util.Collection;
+
+@NotNullByDefault
 public interface ScreenFilterMonitor {
 
+	/**
+	 * Returns the details of all apps that have requested the
+	 * SYSTEM_ALERT_WINDOW permission, excluding system apps, Google Play
+	 * Services, and any apps that have been allowed by calling
+	 * {@link #allowApps(Collection)}.
+	 */
+	@UiThread
+	Collection<AppDetails> getApps();
+
+	/**
+	 * Allows the apps with the given package names to use overlay windows.
+	 * They will not be returned by future calls to {@link #getApps()}.
+	 */
 	@UiThread
-	Set<String> getApps();
+	void allowApps(Collection<String> packageNames);
+
+	class AppDetails {
+
+		public final String name;
+		public final String packageName;
+
+		public AppDetails(String name, String packageName) {
+			this.name = name;
+			this.packageName = packageName;
+		}
+	}
 }
diff --git a/briar-android/src/main/res/layout/dialog_screen_filter.xml b/briar-android/src/main/res/layout/dialog_screen_filter.xml
new file mode 100644
index 0000000000..c09d0dea79
--- /dev/null
+++ b/briar-android/src/main/res/layout/dialog_screen_filter.xml
@@ -0,0 +1,26 @@
+<?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:orientation="vertical"
+              android:padding="@dimen/margin_large">
+
+	<ScrollView
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content">
+
+		<TextView
+			android:id="@+id/screen_filter_message"
+			android:layout_width="match_parent"
+			android:layout_height="wrap_content"/>
+
+	</ScrollView>
+
+	<CheckBox
+		android:id="@+id/screen_filter_checkbox"
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content"
+		android:layout_marginTop="@dimen/margin_large"
+		android:text="@string/screen_filter_allow"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/briar-android/src/main/res/values/strings.xml b/briar-android/src/main/res/values/strings.xml
index 97da612ac0..7f27eeada1 100644
--- a/briar-android/src/main/res/values/strings.xml
+++ b/briar-android/src/main/res/values/strings.xml
@@ -397,6 +397,7 @@
 	<!-- Screen Filters & Tapjacking -->
 	<string name="screen_filter_title">Screen overlay detected</string>
 	<string name="screen_filter_body">Another app is drawing on top of Briar. To protect your security, Briar will not respond to touches when another app is drawing on top.\n\nTry turning off the following apps when using Briar:\n\n%1$s</string>
+	<string name="screen_filter_allow">Allow these apps to draw on top</string>
 
 	<!-- Permission Requests -->
 	<string name="permission_camera_title">Camera permission</string>
-- 
GitLab