1212import android .content .Context ;
1313import android .content .ContextWrapper ;
1414import android .content .MutableContextWrapper ;
15- import android .graphics .Rect ;
1615import android .graphics .drawable .ColorDrawable ;
1716import android .os .Bundle ;
1817import android .view .Display ;
19- import android .view .Gravity ;
2018import android .view .View ;
21- import android .view .ViewGroup ;
2219import android .view .WindowManager ;
2320import android .view .accessibility .AccessibilityEvent ;
2421import android .view .inputmethod .InputMethodManager ;
2724import androidx .annotation .NonNull ;
2825import androidx .annotation .Nullable ;
2926import io .flutter .Log ;
30- import java .lang .reflect .InvocationHandler ;
31- import java .lang .reflect .InvocationTargetException ;
32- import java .lang .reflect .Method ;
33- import java .lang .reflect .Proxy ;
3427
3528/*
3629 * A presentation used for hosting a single Android view in a virtual display.
@@ -68,7 +61,7 @@ static class PresentationState {
6861
6962 // Contains views that were added directly to the window manager (e.g
7063 // android.widget.PopupWindow).
71- private FakeWindowViewGroup fakeWindowViewGroup ;
64+ private SingleViewFakeWindowViewGroup fakeWindowViewGroup ;
7265 }
7366
7467 // A reference to the current accessibility bridge to which accessibility events will be
@@ -153,7 +146,7 @@ protected void onCreate(Bundle savedInstanceState) {
153146 // This makes sure we preserve alpha for the VD's content.
154147 getWindow ().setBackgroundDrawable (new ColorDrawable (android .graphics .Color .TRANSPARENT ));
155148 if (state .fakeWindowViewGroup == null ) {
156- state .fakeWindowViewGroup = new FakeWindowViewGroup (getContext ());
149+ state .fakeWindowViewGroup = new SingleViewFakeWindowViewGroup (getContext ());
157150 }
158151 if (state .windowManagerHandler == null ) {
159152 WindowManager windowManagerDelegate =
@@ -223,59 +216,6 @@ public PlatformView getView() {
223216 return state .platformView ;
224217 }
225218
226- /*
227- * A view group that implements the same layout protocol that exist between the WindowManager and its direct
228- * children.
229- *
230- * Currently only a subset of the protocol is supported (gravity, x, and y).
231- */
232- static class FakeWindowViewGroup extends ViewGroup {
233- // Used in onLayout to keep the bounds of the current view.
234- // We keep it as a member to avoid object allocations during onLayout which are discouraged.
235- private final Rect viewBounds ;
236-
237- // Used in onLayout to keep the bounds of the child views.
238- // We keep it as a member to avoid object allocations during onLayout which are discouraged.
239- private final Rect childRect ;
240-
241- public FakeWindowViewGroup (Context context ) {
242- super (context );
243- viewBounds = new Rect ();
244- childRect = new Rect ();
245- }
246-
247- @ Override
248- protected void onLayout (boolean changed , int l , int t , int r , int b ) {
249- for (int i = 0 ; i < getChildCount (); i ++) {
250- View child = getChildAt (i );
251- WindowManager .LayoutParams params = (WindowManager .LayoutParams ) child .getLayoutParams ();
252- viewBounds .set (l , t , r , b );
253- Gravity .apply (
254- params .gravity ,
255- child .getMeasuredWidth (),
256- child .getMeasuredHeight (),
257- viewBounds ,
258- params .x ,
259- params .y ,
260- childRect );
261- child .layout (childRect .left , childRect .top , childRect .right , childRect .bottom );
262- }
263- }
264-
265- @ Override
266- protected void onMeasure (int widthMeasureSpec , int heightMeasureSpec ) {
267- for (int i = 0 ; i < getChildCount (); i ++) {
268- View child = getChildAt (i );
269- child .measure (atMost (widthMeasureSpec ), atMost (heightMeasureSpec ));
270- }
271- super .onMeasure (widthMeasureSpec , heightMeasureSpec );
272- }
273-
274- private static int atMost (int measureSpec ) {
275- return MeasureSpec .makeMeasureSpec (MeasureSpec .getSize (measureSpec ), MeasureSpec .AT_MOST );
276- }
277- }
278-
279219 /** Answers calls for {@link InputMethodManager} with an instance cached at creation time. */
280220 // TODO(mklim): This caches the IMM at construction time and won't pick up any changes. In rare
281221 // cases where the FlutterView changes windows this will return an outdated instance. This
@@ -354,7 +294,7 @@ public Object getSystemService(String name) {
354294
355295 private WindowManager getWindowManager () {
356296 if (windowManager == null ) {
357- windowManager = windowManagerHandler . getWindowManager () ;
297+ windowManager = windowManagerHandler ;
358298 }
359299 return windowManager ;
360300 }
@@ -371,101 +311,6 @@ private boolean isCalledFromAlertDialog() {
371311 }
372312 }
373313
374- /*
375- * A dynamic proxy handler for a WindowManager with custom overrides.
376- *
377- * The presentation's window manager delegates all calls to the default window manager.
378- * WindowManager#addView calls triggered by views that are attached to the virtual display are crashing
379- * (see: https://github.com/flutter/flutter/issues/20714). This was triggered when selecting text in an embedded
380- * WebView (as the selection handles are implemented as popup windows).
381- *
382- * This dynamic proxy overrides the addView, removeView, removeViewImmediate, and updateViewLayout methods
383- * to prevent these crashes.
384- *
385- * This will be more efficient as a static proxy that's not using reflection, but as the engine is currently
386- * not being built against the latest Android SDK we cannot override all relevant method.
387- * Tracking issue for upgrading the engine's Android sdk: https://github.com/flutter/flutter/issues/20717
388- */
389- static class WindowManagerHandler implements InvocationHandler {
390- private static final String TAG = "PlatformViewsController" ;
391-
392- private final WindowManager delegate ;
393- FakeWindowViewGroup fakeWindowRootView ;
394-
395- WindowManagerHandler (WindowManager delegate , FakeWindowViewGroup fakeWindowViewGroup ) {
396- this .delegate = delegate ;
397- fakeWindowRootView = fakeWindowViewGroup ;
398- }
399-
400- public WindowManager getWindowManager () {
401- return (WindowManager )
402- Proxy .newProxyInstance (
403- WindowManager .class .getClassLoader (), new Class <?>[] {WindowManager .class }, this );
404- }
405-
406- @ Override
407- public Object invoke (Object proxy , Method method , Object [] args ) throws Throwable {
408- switch (method .getName ()) {
409- case "addView" :
410- addView (args );
411- return null ;
412- case "removeView" :
413- removeView (args );
414- return null ;
415- case "removeViewImmediate" :
416- removeViewImmediate (args );
417- return null ;
418- case "updateViewLayout" :
419- updateViewLayout (args );
420- return null ;
421- }
422- try {
423- return method .invoke (delegate , args );
424- } catch (InvocationTargetException e ) {
425- throw e .getCause ();
426- }
427- }
428-
429- private void addView (Object [] args ) {
430- if (fakeWindowRootView == null ) {
431- Log .w (TAG , "Embedded view called addView while detached from presentation" );
432- return ;
433- }
434- View view = (View ) args [0 ];
435- WindowManager .LayoutParams layoutParams = (WindowManager .LayoutParams ) args [1 ];
436- fakeWindowRootView .addView (view , layoutParams );
437- }
438-
439- private void removeView (Object [] args ) {
440- if (fakeWindowRootView == null ) {
441- Log .w (TAG , "Embedded view called removeView while detached from presentation" );
442- return ;
443- }
444- View view = (View ) args [0 ];
445- fakeWindowRootView .removeView (view );
446- }
447-
448- private void removeViewImmediate (Object [] args ) {
449- if (fakeWindowRootView == null ) {
450- Log .w (TAG , "Embedded view called removeViewImmediate while detached from presentation" );
451- return ;
452- }
453- View view = (View ) args [0 ];
454- view .clearAnimation ();
455- fakeWindowRootView .removeView (view );
456- }
457-
458- private void updateViewLayout (Object [] args ) {
459- if (fakeWindowRootView == null ) {
460- Log .w (TAG , "Embedded view called updateViewLayout while detached from presentation" );
461- return ;
462- }
463- View view = (View ) args [0 ];
464- WindowManager .LayoutParams layoutParams = (WindowManager .LayoutParams ) args [1 ];
465- fakeWindowRootView .updateViewLayout (view , layoutParams );
466- }
467- }
468-
469314 private static class AccessibilityDelegatingFrameLayout extends FrameLayout {
470315 private final AccessibilityEventsDelegate accessibilityEventsDelegate ;
471316 private final View embeddedView ;
0 commit comments