mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-18 05:39:53 +01:00
Add tapjacking protection
* Set filterTouchesWhenObscured for all views * Warn the user if Apps using the SYSTEM_ALERT_WINDOW permission are installed * Warn the user if an App using the permission is installed while Briar is running Signed-off-by: goapunk <noobie@goapunks.net>
This commit is contained in:
@@ -28,6 +28,7 @@ import org.briarproject.briar.BriarCoreModule;
|
|||||||
import org.briarproject.briar.android.reporting.BriarReportSender;
|
import org.briarproject.briar.android.reporting.BriarReportSender;
|
||||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||||
import org.briarproject.briar.api.android.ReferenceManager;
|
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.BlogManager;
|
||||||
import org.briarproject.briar.api.blog.BlogPostFactory;
|
import org.briarproject.briar.api.blog.BlogPostFactory;
|
||||||
import org.briarproject.briar.api.blog.BlogSharingManager;
|
import org.briarproject.briar.api.blog.BlogSharingManager;
|
||||||
@@ -89,6 +90,8 @@ public interface AndroidComponent
|
|||||||
|
|
||||||
AndroidNotificationManager androidNotificationManager();
|
AndroidNotificationManager androidNotificationManager();
|
||||||
|
|
||||||
|
ScreenFilterMonitor screenFilterMonitor();
|
||||||
|
|
||||||
ConnectionRegistry connectionRegistry();
|
ConnectionRegistry connectionRegistry();
|
||||||
|
|
||||||
ContactManager contactManager();
|
ContactManager contactManager();
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import org.briarproject.bramble.api.ui.UiCallback;
|
|||||||
import org.briarproject.bramble.util.StringUtils;
|
import org.briarproject.bramble.util.StringUtils;
|
||||||
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
import org.briarproject.briar.api.android.AndroidNotificationManager;
|
||||||
import org.briarproject.briar.api.android.ReferenceManager;
|
import org.briarproject.briar.api.android.ReferenceManager;
|
||||||
|
import org.briarproject.briar.api.android.ScreenFilterMonitor;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.security.GeneralSecurityException;
|
import java.security.GeneralSecurityException;
|
||||||
@@ -37,6 +38,8 @@ public class AppModule {
|
|||||||
static class EagerSingletons {
|
static class EagerSingletons {
|
||||||
@Inject
|
@Inject
|
||||||
AndroidNotificationManager androidNotificationManager;
|
AndroidNotificationManager androidNotificationManager;
|
||||||
|
@Inject
|
||||||
|
ScreenFilterMonitor screenFilterMonitor;
|
||||||
}
|
}
|
||||||
|
|
||||||
private final Application application;
|
private final Application application;
|
||||||
@@ -166,4 +169,12 @@ public class AppModule {
|
|||||||
eventBus.addListener(notificationManager);
|
eventBus.addListener(notificationManager);
|
||||||
return notificationManager;
|
return notificationManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
ScreenFilterMonitor provideScreenFilterMonitor(
|
||||||
|
LifecycleManager lifecycleManager, ScreenFilterMonitorImpl sfm) {
|
||||||
|
lifecycleManager.registerService(sfm);
|
||||||
|
return sfm;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,11 +13,15 @@ import org.briarproject.briar.android.BriarApplication;
|
|||||||
import org.briarproject.briar.android.DestroyableContext;
|
import org.briarproject.briar.android.DestroyableContext;
|
||||||
import org.briarproject.briar.android.controller.ActivityLifecycleController;
|
import org.briarproject.briar.android.controller.ActivityLifecycleController;
|
||||||
import org.briarproject.briar.android.forum.ForumModule;
|
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.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
|
import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
|
||||||
import static android.view.inputmethod.InputMethodManager.SHOW_IMPLICIT;
|
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
|
public abstract class BaseActivity extends AppCompatActivity
|
||||||
implements DestroyableContext {
|
implements DestroyableContext {
|
||||||
|
|
||||||
protected ActivityComponent activityComponent;
|
protected ActivityComponent activityComponent;
|
||||||
|
|
||||||
private final List<ActivityLifecycleController> lifecycleControllers =
|
private final List<ActivityLifecycleController> lifecycleControllers =
|
||||||
new ArrayList<>();
|
new ArrayList<>();
|
||||||
private boolean destroyed = false;
|
private boolean destroyed = false;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
protected ScreenFilterMonitor screenFilterMonitor;
|
||||||
|
private SFDialogFragment dialogFrag;
|
||||||
|
|
||||||
public abstract void injectActivity(ActivityComponent component);
|
public abstract void injectActivity(ActivityComponent component);
|
||||||
|
|
||||||
public void addLifecycleController(ActivityLifecycleController alc) {
|
public void addLifecycleController(ActivityLifecycleController alc) {
|
||||||
@@ -58,6 +65,7 @@ public abstract class BaseActivity extends AppCompatActivity
|
|||||||
for (ActivityLifecycleController alc : lifecycleControllers) {
|
for (ActivityLifecycleController alc : lifecycleControllers) {
|
||||||
alc.onActivityCreate(this);
|
alc.onActivityCreate(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ActivityComponent getActivityComponent() {
|
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
|
@Override
|
||||||
protected void onDestroy() {
|
protected void onDestroy() {
|
||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -83,6 +83,10 @@ public class SplashScreenActivity extends BaseActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void showNewScreenFilterWarning() {
|
||||||
|
}
|
||||||
|
|
||||||
private void enableStrictMode() {
|
private void enableStrictMode() {
|
||||||
if (TESTING) {
|
if (TESTING) {
|
||||||
ThreadPolicy.Builder threadPolicy = new ThreadPolicy.Builder();
|
ThreadPolicy.Builder threadPolicy = new ThreadPolicy.Builder();
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
40
briar-android/src/main/res/layout/alert_dialog_checkbox.xml
Normal file
40
briar-android/src/main/res/layout/alert_dialog_checkbox.xml
Normal file
@@ -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>
|
||||||
@@ -380,4 +380,10 @@
|
|||||||
<!-- Sign Out -->
|
<!-- Sign Out -->
|
||||||
<string name="progress_title_logout">Signing out of Briar…</string>
|
<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>
|
</resources>
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
<item name="android:textColorTertiaryInverse">@color/briar_text_tertiary_inverse</item>
|
<item name="android:textColorTertiaryInverse">@color/briar_text_tertiary_inverse</item>
|
||||||
<item name="android:textColorLink">@color/briar_text_link</item>
|
<item name="android:textColorLink">@color/briar_text_link</item>
|
||||||
<item name="android:windowAnimationStyle">@style/ActivityAnimation</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 -->
|
<!-- These fix a long-standing UI bug in the support preference library -->
|
||||||
<item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>
|
<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:textColorTertiaryInverse">@color/briar_text_tertiary_inverse</item>
|
||||||
<item name="android:textColorLink">@color/briar_text_link</item>
|
<item name="android:textColorLink">@color/briar_text_link</item>
|
||||||
<item name="android:windowAnimationStyle">@style/DialogAnimation</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>
|
||||||
|
|
||||||
<style name="DialogAnimation" parent="@android:style/Animation.Dialog">
|
<style name="DialogAnimation" parent="@android:style/Animation.Dialog">
|
||||||
|
|||||||
Reference in New Issue
Block a user