Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit bd01246

Browse files
authored
[Re-land] Remove WindowManager reflection in SingleViewPresentation.java (#50890)
relands #49996 Context b/326363243 [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
1 parent 728aa4e commit bd01246

File tree

7 files changed

+354
-158
lines changed

7 files changed

+354
-158
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36291,8 +36291,11 @@ ORIGIN: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/Platf
3629136291
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/PlatformViewWrapper.java + ../../../flutter/LICENSE
3629236292
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/PlatformViewsAccessibilityDelegate.java + ../../../flutter/LICENSE
3629336293
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java + ../../../flutter/LICENSE
36294+
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/SingleViewFakeWindowViewGroup.java + ../../../flutter/LICENSE
3629436295
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/SingleViewPresentation.java + ../../../flutter/LICENSE
36296+
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/SingleViewWindowManager.java + ../../../flutter/LICENSE
3629536297
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/VirtualDisplayController.java + ../../../flutter/LICENSE
36298+
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/WindowManagerHandler.java + ../../../flutter/LICENSE
3629636299
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/plugin/text/ProcessTextPlugin.java + ../../../flutter/LICENSE
3629736300
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/util/HandlerCompat.java + ../../../flutter/LICENSE
3629836301
ORIGIN: ../../../flutter/shell/platform/android/io/flutter/util/PathUtils.java + ../../../flutter/LICENSE
@@ -39156,10 +39159,13 @@ FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/Platfor
3915639159
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/PlatformViewWrapper.java
3915739160
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/PlatformViewsAccessibilityDelegate.java
3915839161
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/PlatformViewsController.java
39162+
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/SingleViewFakeWindowViewGroup.java
3915939163
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/SingleViewPresentation.java
39164+
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/SingleViewWindowManager.java
3916039165
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/SurfaceProducerPlatformViewRenderTarget.java
3916139166
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/SurfaceTexturePlatformViewRenderTarget.java
3916239167
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/VirtualDisplayController.java
39168+
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/platform/WindowManagerHandler.java
3916339169
FILE: ../../../flutter/shell/platform/android/io/flutter/plugin/text/ProcessTextPlugin.java
3916439170
FILE: ../../../flutter/shell/platform/android/io/flutter/util/HandlerCompat.java
3916539171
FILE: ../../../flutter/shell/platform/android/io/flutter/util/PathUtils.java

shell/platform/android/BUILD.gn

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,10 +324,13 @@ android_java_sources = [
324324
"io/flutter/plugin/platform/PlatformViewWrapper.java",
325325
"io/flutter/plugin/platform/PlatformViewsAccessibilityDelegate.java",
326326
"io/flutter/plugin/platform/PlatformViewsController.java",
327+
"io/flutter/plugin/platform/SingleViewFakeWindowViewGroup.java",
327328
"io/flutter/plugin/platform/SingleViewPresentation.java",
329+
"io/flutter/plugin/platform/SingleViewWindowManager.java",
328330
"io/flutter/plugin/platform/SurfaceProducerPlatformViewRenderTarget.java",
329331
"io/flutter/plugin/platform/SurfaceTexturePlatformViewRenderTarget.java",
330332
"io/flutter/plugin/platform/VirtualDisplayController.java",
333+
"io/flutter/plugin/platform/WindowManagerHandler.java",
331334
"io/flutter/plugin/text/ProcessTextPlugin.java",
332335
"io/flutter/util/HandlerCompat.java",
333336
"io/flutter/util/PathUtils.java",
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
package io.flutter.plugin.platform;
6+
7+
import android.content.Context;
8+
import android.graphics.Rect;
9+
import android.view.Gravity;
10+
import android.view.View;
11+
import android.view.ViewGroup;
12+
import android.view.WindowManager;
13+
14+
/*
15+
* A view group that implements the same layout protocol that exist between the WindowManager and its direct
16+
* children.
17+
*
18+
* Currently only a subset of the protocol is supported (gravity, x, and y).
19+
*/
20+
class SingleViewFakeWindowViewGroup extends ViewGroup {
21+
// Used in onLayout to keep the bounds of the current view.
22+
// We keep it as a member to avoid object allocations during onLayout which are discouraged.
23+
private final Rect viewBounds;
24+
25+
// Used in onLayout to keep the bounds of the child views.
26+
// We keep it as a member to avoid object allocations during onLayout which are discouraged.
27+
private final Rect childRect;
28+
29+
public SingleViewFakeWindowViewGroup(Context context) {
30+
super(context);
31+
viewBounds = new Rect();
32+
childRect = new Rect();
33+
}
34+
35+
@Override
36+
protected void onLayout(boolean changed, int l, int t, int r, int b) {
37+
for (int i = 0; i < getChildCount(); i++) {
38+
View child = getChildAt(i);
39+
WindowManager.LayoutParams params = (WindowManager.LayoutParams) child.getLayoutParams();
40+
viewBounds.set(l, t, r, b);
41+
Gravity.apply(
42+
params.gravity,
43+
child.getMeasuredWidth(),
44+
child.getMeasuredHeight(),
45+
viewBounds,
46+
params.x,
47+
params.y,
48+
childRect);
49+
child.layout(childRect.left, childRect.top, childRect.right, childRect.bottom);
50+
}
51+
}
52+
53+
@Override
54+
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
55+
for (int i = 0; i < getChildCount(); i++) {
56+
View child = getChildAt(i);
57+
child.measure(atMost(widthMeasureSpec), atMost(heightMeasureSpec));
58+
}
59+
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
60+
}
61+
62+
private static int atMost(int measureSpec) {
63+
return MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(measureSpec), MeasureSpec.AT_MOST);
64+
}
65+
}

shell/platform/android/io/flutter/plugin/platform/SingleViewPresentation.java

Lines changed: 3 additions & 158 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,10 @@
1212
import android.content.Context;
1313
import android.content.ContextWrapper;
1414
import android.content.MutableContextWrapper;
15-
import android.graphics.Rect;
1615
import android.graphics.drawable.ColorDrawable;
1716
import android.os.Bundle;
1817
import android.view.Display;
19-
import android.view.Gravity;
2018
import android.view.View;
21-
import android.view.ViewGroup;
2219
import android.view.WindowManager;
2320
import android.view.accessibility.AccessibilityEvent;
2421
import android.view.inputmethod.InputMethodManager;
@@ -27,10 +24,6 @@
2724
import androidx.annotation.NonNull;
2825
import androidx.annotation.Nullable;
2926
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;
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

Comments
 (0)