Skip to content

Commit

Permalink
Fix AlertDialogs built by platform views (#17511)
Browse files Browse the repository at this point in the history
  • Loading branch information
amirh authored Apr 6, 2020
1 parent bd76076 commit 2fab00e
Showing 1 changed file with 39 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import static android.view.View.OnFocusChangeListener;

import android.annotation.TargetApi;
import android.app.AlertDialog;
import android.app.Presentation;
import android.content.Context;
import android.content.ContextWrapper;
Expand Down Expand Up @@ -102,6 +103,9 @@ static class PresentationState {

private boolean startFocused = false;

// The context for the application window that hosts FlutterView.
private final Context outerContext;

/**
* Creates a presentation that will use the view factory to create a new platform view in the
* presentation's onCreate, and attach it.
Expand All @@ -120,6 +124,7 @@ public SingleViewPresentation(
this.viewId = viewId;
this.createParams = createParams;
this.focusChangeListener = focusChangeListener;
this.outerContext = outerContext;
state = new PresentationState();
getWindow()
.setFlags(
Expand Down Expand Up @@ -147,6 +152,7 @@ public SingleViewPresentation(
viewFactory = null;
this.state = state;
this.focusChangeListener = focusChangeListener;
this.outerContext = outerContext;
getWindow()
.setFlags(
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
Expand All @@ -173,7 +179,8 @@ protected void onCreate(Bundle savedInstanceState) {

// Our base mContext has already been wrapped with an IMM cache at instantiation time, but
// we want to wrap it again here to also return state.windowManagerHandler.
Context context = new PresentationContext(getContext(), state.windowManagerHandler);
Context context =
new PresentationContext(getContext(), state.windowManagerHandler, outerContext);

if (state.platformView == null) {
state.platformView = viewFactory.create(context, viewId, createParams);
Expand Down Expand Up @@ -304,15 +311,34 @@ public Context createDisplayContext(Display display) {
private static class PresentationContext extends ContextWrapper {
private @NonNull final WindowManagerHandler windowManagerHandler;
private @Nullable WindowManager windowManager;
private final Context flutterAppWindowContext;

PresentationContext(Context base, @NonNull WindowManagerHandler windowManagerHandler) {
PresentationContext(
Context base,
@NonNull WindowManagerHandler windowManagerHandler,
Context flutterAppWindowContext) {
super(base);
this.windowManagerHandler = windowManagerHandler;
this.flutterAppWindowContext = flutterAppWindowContext;
}

@Override
public Object getSystemService(String name) {
if (WINDOW_SERVICE.equals(name)) {
if (isCalledFromAlertDialog()) {
// Alert dialogs are showing on top of the entire application and should not be limited to
// the virtual
// display. If we detect that an android.app.AlertDialog constructor is what's fetching
// the window manager
// we return the one for the application's window.
//
// Note that if we don't do this AlertDialog will throw a ClassCastException as down the
// line it tries
// to case this instance to a WindowManagerImpl which the object returned by
// getWindowManager is not
// a subclass of.
return flutterAppWindowContext.getSystemService(name);
}
return getWindowManager();
}
return super.getSystemService(name);
Expand All @@ -324,6 +350,17 @@ private WindowManager getWindowManager() {
}
return windowManager;
}

private boolean isCalledFromAlertDialog() {
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
for (int i = 0; i < stackTraceElements.length && i < 11; i++) {
if (stackTraceElements[i].getClassName().equals(AlertDialog.class.getCanonicalName())
&& stackTraceElements[i].getMethodName().equals("<init>")) {
return true;
}
}
return false;
}
}

/*
Expand Down

0 comments on commit 2fab00e

Please sign in to comment.