Simplify dialog handling, work around Android bug.

This commit is contained in:
akwizgran
2018-01-22 17:22:04 +00:00
parent dab9a3e73d
commit a50ded2d50
4 changed files with 35 additions and 51 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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) {