12
12
import android .content .Context ;
13
13
import android .content .ContextWrapper ;
14
14
import android .content .MutableContextWrapper ;
15
- import android .graphics .Rect ;
16
15
import android .graphics .drawable .ColorDrawable ;
17
16
import android .os .Bundle ;
18
17
import android .view .Display ;
19
- import android .view .Gravity ;
20
18
import android .view .View ;
21
- import android .view .ViewGroup ;
22
19
import android .view .WindowManager ;
23
20
import android .view .accessibility .AccessibilityEvent ;
24
21
import android .view .inputmethod .InputMethodManager ;
27
24
import androidx .annotation .NonNull ;
28
25
import androidx .annotation .Nullable ;
29
26
import 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 ;
34
27
35
28
/*
36
29
* A presentation used for hosting a single Android view in a virtual display.
@@ -68,7 +61,7 @@ static class PresentationState {
68
61
69
62
// Contains views that were added directly to the window manager (e.g
70
63
// android.widget.PopupWindow).
71
- private FakeWindowViewGroup fakeWindowViewGroup ;
64
+ private SingleViewFakeWindowViewGroup fakeWindowViewGroup ;
72
65
}
73
66
74
67
// A reference to the current accessibility bridge to which accessibility events will be
@@ -153,7 +146,7 @@ protected void onCreate(Bundle savedInstanceState) {
153
146
// This makes sure we preserve alpha for the VD's content.
154
147
getWindow ().setBackgroundDrawable (new ColorDrawable (android .graphics .Color .TRANSPARENT ));
155
148
if (state .fakeWindowViewGroup == null ) {
156
- state .fakeWindowViewGroup = new FakeWindowViewGroup (getContext ());
149
+ state .fakeWindowViewGroup = new SingleViewFakeWindowViewGroup (getContext ());
157
150
}
158
151
if (state .windowManagerHandler == null ) {
159
152
WindowManager windowManagerDelegate =
@@ -223,59 +216,6 @@ public PlatformView getView() {
223
216
return state .platformView ;
224
217
}
225
218
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
-
279
219
/** Answers calls for {@link InputMethodManager} with an instance cached at creation time. */
280
220
// TODO(mklim): This caches the IMM at construction time and won't pick up any changes. In rare
281
221
// cases where the FlutterView changes windows this will return an outdated instance. This
@@ -354,7 +294,7 @@ public Object getSystemService(String name) {
354
294
355
295
private WindowManager getWindowManager () {
356
296
if (windowManager == null ) {
357
- windowManager = windowManagerHandler . getWindowManager () ;
297
+ windowManager = windowManagerHandler ;
358
298
}
359
299
return windowManager ;
360
300
}
@@ -371,101 +311,6 @@ private boolean isCalledFromAlertDialog() {
371
311
}
372
312
}
373
313
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
-
469
314
private static class AccessibilityDelegatingFrameLayout extends FrameLayout {
470
315
private final AccessibilityEventsDelegate accessibilityEventsDelegate ;
471
316
private final View embeddedView ;
0 commit comments