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 b4352e71f2e9ccf92a61b7c726f1e299c93fe84e..7c8f5061ae0c8777f3bebd1679174dba8e545a39 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 @@ -4,6 +4,7 @@ import android.os.Bundle; import android.os.IBinder; import android.support.annotation.LayoutRes; import android.support.annotation.UiThread; +import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; @@ -21,6 +22,7 @@ import org.briarproject.briar.android.controller.ActivityLifecycleController; import org.briarproject.briar.android.forum.ForumModule; import org.briarproject.briar.android.fragment.BaseFragment; import org.briarproject.briar.android.fragment.ScreenFilterDialogFragment; +import org.briarproject.briar.android.util.UiUtils; import org.briarproject.briar.android.widget.TapSafeFrameLayout; import org.briarproject.briar.android.widget.TapSafeFrameLayout.OnTapFilteredListener; import org.briarproject.briar.api.android.ScreenFilterMonitor; @@ -41,8 +43,6 @@ import static org.briarproject.briar.android.TestingConstants.PREVENT_SCREENSHOT public abstract class BaseActivity extends AppCompatActivity implements DestroyableContext, OnTapFilteredListener { - private static final String STATE_SHOULD_SHOW_DIALOG = "shouldShowDialog"; - @Inject protected ScreenFilterMonitor screenFilterMonitor; @@ -52,10 +52,6 @@ public abstract class BaseActivity extends AppCompatActivity new ArrayList<>(); private boolean destroyed = false; - @Nullable - private ScreenFilterDialogFragment dialogFrag = null; - private boolean shouldShowDialog = false; - @Nullable private Toolbar toolbar = null; private boolean searchedForToolbar = false; @@ -86,15 +82,6 @@ public abstract class BaseActivity extends AppCompatActivity for (ActivityLifecycleController alc : lifecycleControllers) { alc.onActivityCreate(this); } - - if (state != null) - shouldShowDialog = state.getBoolean(STATE_SHOULD_SHOW_DIALOG); - } - - @Override - protected void onSaveInstanceState(Bundle state) { - super.onSaveInstanceState(state); - state.putBoolean(STATE_SHOULD_SHOW_DIALOG, shouldShowDialog); } public ActivityComponent getActivityComponent() { @@ -116,6 +103,16 @@ public abstract class BaseActivity extends AppCompatActivity for (ActivityLifecycleController alc : lifecycleControllers) { alc.onActivityStart(); } + protectToolbar(); + ScreenFilterDialogFragment f = findDialogFragment(); + if (f != null) f.setDismissListener(this::protectToolbar); + } + + @Nullable + private ScreenFilterDialogFragment findDialogFragment() { + Fragment f = getSupportFragmentManager().findFragmentByTag( + ScreenFilterDialogFragment.TAG); + return (ScreenFilterDialogFragment) f; } @Override @@ -126,23 +123,6 @@ public abstract class BaseActivity extends AppCompatActivity } } - @Override - protected void onResume() { - super.onResume(); - protectToolbar(); - if (shouldShowDialog) showScreenFilterWarning(); - } - - @Override - protected void onPause() { - super.onPause(); - if (dialogFrag != null) { - dialogFrag.dismiss(); - dialogFrag = null; - shouldShowDialog = true; // Show dialog again on resume - } - } - protected void showInitialFragment(BaseFragment f) { getSupportFragmentManager().beginTransaction() .replace(R.id.fragmentContainer, f, f.getUniqueTag()) @@ -161,29 +141,22 @@ public abstract class BaseActivity extends AppCompatActivity private boolean showScreenFilterWarning() { // If the dialog is already visible, filter the tap - if (dialogFrag != null) return false; + ScreenFilterDialogFragment f = findDialogFragment(); + if (f != null && f.isVisible()) return false; Collection<AppDetails> apps = screenFilterMonitor.getApps(); // If all overlay apps have been allowed, allow the tap - if (apps.isEmpty()) { - shouldShowDialog = false; // May have been true when state was saved - return true; - } + if (apps.isEmpty()) return true; // Show dialog unless onSaveInstanceState() has been called, see #1112 FragmentManager fm = getSupportFragmentManager(); if (!fm.isStateSaved()) { // Create dialog - dialogFrag = ScreenFilterDialogFragment.newInstance(apps); - shouldShowDialog = true; + f = ScreenFilterDialogFragment.newInstance(apps); // When dialog is dismissed, update protection of toolbar - dialogFrag.setDismissListener(() -> { - dialogFrag = null; - shouldShowDialog = false; - protectToolbar(); - }); + f.setDismissListener(this::protectToolbar); // Hide soft keyboard when (re)showing dialog View focus = getCurrentFocus(); if (focus != null) hideSoftKeyboard(focus); - dialogFrag.show(fm, dialogFrag.getTag()); + f.show(fm, ScreenFilterDialogFragment.TAG); } // Filter the tap return false; @@ -243,7 +216,7 @@ public abstract class BaseActivity extends AppCompatActivity findToolbar(); if (toolbar != null) { boolean filter = !screenFilterMonitor.getApps().isEmpty(); - toolbar.setFilterTouchesWhenObscured(filter); + UiUtils.setFilterTouchesWhenObscured(toolbar, filter); } } @@ -257,6 +230,8 @@ public abstract class BaseActivity extends AppCompatActivity @Nullable private Toolbar findToolbar(ViewGroup vg) { + // Views inside tap-safe layouts are already protected + if (vg instanceof TapSafeFrameLayout) return null; for (int i = 0, len = vg.getChildCount(); i < len; i++) { View child = vg.getChildAt(i); if (child instanceof Toolbar) return (Toolbar) child; 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 810f61f39fd654c16baf400f7e1888f7c9d7dc31..b7c6116653ed3d7540e0553b2b2c1426d03a05ac 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 @@ -30,6 +30,8 @@ import javax.inject.Inject; @ParametersNotNullByDefault public class ScreenFilterDialogFragment extends DialogFragment { + public static final String TAG = ScreenFilterDialogFragment.class.getName(); + @Inject ScreenFilterMonitor screenFilterMonitor; 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 7e31452feb806b53346f46187cf432dbf41803e0..d6ef54126d5b75a3e23791ece4ef796e13249f09 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 @@ -6,7 +6,6 @@ import android.content.Context; import android.content.DialogInterface.OnClickListener; import android.content.Intent; import android.net.Uri; -import android.os.Build; import android.os.PowerManager; import android.support.design.widget.TextInputLayout; import android.support.v4.app.FragmentManager; @@ -162,7 +161,7 @@ public class UiUtils { } public static boolean needsDozeWhitelisting(Context ctx) { - if (Build.VERSION.SDK_INT < 23) return false; + if (SDK_INT < 23) return false; PowerManager pm = (PowerManager) ctx.getSystemService(POWER_SERVICE); String packageName = ctx.getPackageName(); if (pm == null) throw new AssertionError(); @@ -182,4 +181,11 @@ public class UiUtils { return SDK_INT == 24 && MANUFACTURER.equalsIgnoreCase("Samsung"); } + public static void setFilterTouchesWhenObscured(View v, boolean filter) { + v.setFilterTouchesWhenObscured(filter); + // Workaround for Android bug #13530806, see + // https://android.googlesource.com/platform/frameworks/base/+/aba566589e0011c4b973c0d4f77be4e9ee176089%5E%21/core/java/android/view/View.java + if (v.getFilterTouchesWhenObscured() != filter) + v.setFilterTouchesWhenObscured(!filter); + } } 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 701406e1fa1f838cd6bbea3f01cbdab0bd1738dd..6d285682f438aec5207d9adc678af41f699ac443 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 @@ -7,6 +7,7 @@ import android.view.MotionEvent; import android.widget.FrameLayout; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.briar.android.util.UiUtils; import javax.annotation.Nullable; @@ -20,18 +21,18 @@ public class TapSafeFrameLayout extends FrameLayout { public TapSafeFrameLayout(Context context) { super(context); - setFilterTouchesWhenObscured(false); + UiUtils.setFilterTouchesWhenObscured(this, false); } public TapSafeFrameLayout(Context context, @Nullable AttributeSet attrs) { super(context, attrs); - setFilterTouchesWhenObscured(false); + UiUtils.setFilterTouchesWhenObscured(this, false); } public TapSafeFrameLayout(Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) { super(context, attrs, defStyleAttr); - setFilterTouchesWhenObscured(false); + UiUtils.setFilterTouchesWhenObscured(this, false); } public void setOnTapFilteredListener(OnTapFilteredListener listener) {