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

Commit 26fc606

Browse files
author
Emmanuel Garcia
committed
Implement onDisplayPlatformView
1 parent de74f8a commit 26fc606

File tree

2 files changed

+138
-36
lines changed

2 files changed

+138
-36
lines changed

shell/platform/android/io/flutter/embedding/engine/systemchannels/PlatformViewsChannel.java

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -80,29 +80,47 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result
8080

8181
private void create(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
8282
Map<String, Object> createArgs = call.arguments();
83+
double width = (createArgs.containsKey("width")) ? (double) createArgs.get("width") : 0;
84+
double height =
85+
(createArgs.containsKey("height")) ? (double) createArgs.get("height") : 0;
86+
boolean usesHybridComposition =
87+
createArgs.containsKey("hybrid") && (boolean) createArgs.get("hybrid");
88+
8389
PlatformViewCreationRequest request =
8490
new PlatformViewCreationRequest(
8591
(int) createArgs.get("id"),
8692
(String) createArgs.get("viewType"),
87-
(double) createArgs.get("width"),
88-
(double) createArgs.get("height"),
93+
width,
94+
height,
8995
(int) createArgs.get("direction"),
9096
createArgs.containsKey("params")
9197
? ByteBuffer.wrap((byte[]) createArgs.get("params"))
9298
: null);
93-
9499
try {
95-
long textureId = handler.createPlatformView(request);
96-
result.success(textureId);
100+
if (usesHybridComposition) {
101+
handler.createAndroidViewForPlatformView(request);
102+
result.success(null);
103+
} else {
104+
long textureId = handler.createVirtualDisplayForPlatformView(request);
105+
result.success(textureId);
106+
}
97107
} catch (IllegalStateException exception) {
98108
result.error("error", detailedExceptionString(exception), null);
99109
}
100110
}
101111

102112
private void dispose(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
103-
int viewId = call.arguments();
113+
Map<String, Object> disposeArgs = call.arguments();
114+
int viewId = (int) disposeArgs.get("id");
115+
boolean usesHybridComposition =
116+
disposeArgs.containsKey("hybrid") && (boolean) disposeArgs.get("hybrid");
117+
104118
try {
105-
handler.disposePlatformView(viewId);
119+
if (usesHybridComposition) {
120+
handler.disposeAndroidViewForPlatformView(viewId);
121+
} else {
122+
handler.disposeVirtualDisplayForPlatformView(viewId);
123+
}
106124
result.success(null);
107125
} catch (IllegalStateException exception) {
108126
result.error("error", detailedExceptionString(exception), null);
@@ -216,18 +234,29 @@ public interface PlatformViewsHandler {
216234
* The Flutter application would like to display a new Android {@code View}, i.e., platform
217235
* view.
218236
*
219-
* <p>The handler should instantiate the desired Android {@code View}, create a new {@link
220-
* io.flutter.view.FlutterView.SurfaceTextureRegistryEntry} within the given Flutter execution
221-
* context, and then return the new texture's ID.
237+
* <p>The Android {@code View} is added to the view hierarchy.
222238
*/
223-
// TODO(mattcarroll): Introduce an annotation for @TextureId
224-
long createPlatformView(@NonNull PlatformViewCreationRequest request);
239+
void createAndroidViewForPlatformView(@NonNull PlatformViewCreationRequest request);
225240

226241
/**
227-
* The Flutter application could like dispose of an existing Android {@code View}, i.e.,
228-
* platform view.
242+
* The Flutter application would like dispose of an existing Android {@code View} rendered in
243+
* the view hierarchy.
229244
*/
230-
void disposePlatformView(int viewId);
245+
void disposeAndroidViewForPlatformView(int viewId);
246+
247+
/**
248+
* The Flutter application would like to display a new Android {@code View}.
249+
*
250+
* <p>{@code View} is added to a {@code VirtualDisplay}. The framework uses id returned by this
251+
* method to lookup the texture in the engine.
252+
*/
253+
long createVirtualDisplayForPlatformView(@NonNull PlatformViewCreationRequest request);
254+
255+
/**
256+
* The Flutter application would like dispose of an existing Android {@code View} rendered in a
257+
* virtual display.
258+
*/
259+
void disposeVirtualDisplayForPlatformView(int viewId);
231260

232261
/**
233262
* The Flutter application would like to resize an existing Android {@code View}, i.e., platform
@@ -279,6 +308,7 @@ public static class PlatformViewCreationRequest {
279308
/** Custom parameters that are unique to the desired platform view. */
280309
@Nullable public final ByteBuffer params;
281310

311+
/** Creates a request to construct a platform view that uses a virtual display. */
282312
public PlatformViewCreationRequest(
283313
int viewId,
284314
@NonNull String viewType,
@@ -295,7 +325,11 @@ public PlatformViewCreationRequest(
295325
}
296326
}
297327

298-
/** Request sent from Flutter to resize a platform view. */
328+
/**
329+
* Request sent from Flutter to resize a platform view.
330+
*
331+
* <p>This only applies to platform views that use virtual displays.
332+
*/
299333
public static class PlatformViewResizeRequest {
300334
/** The ID of the platform view as seen by the Flutter side. */
301335
public final int viewId;

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

Lines changed: 88 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,6 @@
4444
public class PlatformViewsController implements PlatformViewsAccessibilityDelegate {
4545
private static final String TAG = "PlatformViewsController";
4646

47-
// API level 20 is required for VirtualDisplay#setSurface which we use when resizing a platform
48-
// view.
49-
private static final int MINIMAL_SDK = Build.VERSION_CODES.KITKAT_WATCH;
50-
5147
private final PlatformViewRegistryImpl registry;
5248

5349
// The context of the Activity or Fragment hosting the render target for the Flutter engine.
@@ -80,6 +76,9 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega
8076
// it is associated with(e.g if a platform view creates other views in the same virtual display.
8177
private final HashMap<Context, View> contextToPlatformView;
8278

79+
private final SparseArray<PlatformViewsChannel.PlatformViewCreationRequest> platformViewRequests;
80+
private final SparseArray<View> platformViews;
81+
8382
// Map of unique IDs to views that render overlay layers.
8483
private final SparseArray<FlutterImageView> overlayLayerViews;
8584

@@ -94,12 +93,34 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega
9493

9594
private final PlatformViewsChannel.PlatformViewsHandler channelHandler =
9695
new PlatformViewsChannel.PlatformViewsHandler() {
97-
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
96+
9897
@Override
99-
public long createPlatformView(
98+
public void createAndroidViewForPlatformView(
10099
@NonNull PlatformViewsChannel.PlatformViewCreationRequest request) {
101-
ensureValidAndroidVersion();
100+
// API level 19 is required for android.graphics.ImageReader.
101+
ensureValidAndroidVersion(Build.VERSION_CODES.KITKAT);
102+
platformViewRequests.put(request.viewId, request);
103+
}
104+
105+
@Override
106+
public void disposeAndroidViewForPlatformView(int viewId) {
107+
// Hybrid view.
108+
if (platformViewRequests.get(viewId) != null) {
109+
platformViewRequests.remove(viewId);
110+
}
111+
if (platformViews.get(viewId) != null) {
112+
((FlutterView) flutterView).addView(platformViews.get(viewId));
113+
platformViews.remove(viewId);
114+
}
115+
}
102116

117+
@Override
118+
public long createVirtualDisplayForPlatformView(
119+
@NonNull PlatformViewsChannel.PlatformViewCreationRequest request) {
120+
// API level 20 is required for VirtualDisplay#setSurface which we use when resizing a
121+
// platform
122+
// view.
123+
ensureValidAndroidVersion(Build.VERSION_CODES.KITKAT_WATCH);
103124
if (!validateDirection(request.direction)) {
104125
throw new IllegalStateException(
105126
"Trying to create a view with unknown direction value: "
@@ -171,9 +192,8 @@ public long createPlatformView(
171192
}
172193

173194
@Override
174-
public void disposePlatformView(int viewId) {
175-
ensureValidAndroidVersion();
176-
195+
public void disposeVirtualDisplayForPlatformView(int viewId) {
196+
ensureValidAndroidVersion(Build.VERSION_CODES.KITKAT_WATCH);
177197
VirtualDisplayController vdController = vdControllers.get(viewId);
178198
if (vdController == null) {
179199
throw new IllegalStateException(
@@ -193,7 +213,7 @@ public void disposePlatformView(int viewId) {
193213
public void resizePlatformView(
194214
@NonNull PlatformViewsChannel.PlatformViewResizeRequest request,
195215
@NonNull Runnable onComplete) {
196-
ensureValidAndroidVersion();
216+
ensureValidAndroidVersion(Build.VERSION_CODES.KITKAT_WATCH);
197217

198218
final VirtualDisplayController vdController = vdControllers.get(request.viewId);
199219
if (vdController == null) {
@@ -224,8 +244,6 @@ public void run() {
224244

225245
@Override
226246
public void onTouch(@NonNull PlatformViewsChannel.PlatformViewTouch touch) {
227-
ensureValidAndroidVersion();
228-
229247
float density = context.getResources().getDisplayMetrics().density;
230248
PointerProperties[] pointerProperties =
231249
parsePointerPropertiesList(touch.rawPointerPropertiesList)
@@ -256,14 +274,12 @@ public void onTouch(@NonNull PlatformViewsChannel.PlatformViewTouch touch) {
256274
touch.source,
257275
touch.flags);
258276

277+
ensureValidAndroidVersion(Build.VERSION_CODES.KITKAT_WATCH);
259278
vdControllers.get(touch.viewId).dispatchTouchEvent(event);
260279
}
261280

262-
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1)
263281
@Override
264282
public void setDirection(int viewId, int direction) {
265-
ensureValidAndroidVersion();
266-
267283
if (!validateDirection(direction)) {
268284
throw new IllegalStateException(
269285
"Trying to set unknown direction value: "
@@ -273,6 +289,7 @@ public void setDirection(int viewId, int direction) {
273289
+ ")");
274290
}
275291

292+
ensureValidAndroidVersion(Build.VERSION_CODES.KITKAT_WATCH);
276293
View view = vdControllers.get(viewId).getView();
277294
if (view == null) {
278295
throw new IllegalStateException(
@@ -284,17 +301,18 @@ public void setDirection(int viewId, int direction) {
284301

285302
@Override
286303
public void clearFocus(int viewId) {
304+
ensureValidAndroidVersion(Build.VERSION_CODES.KITKAT_WATCH);
287305
View view = vdControllers.get(viewId).getView();
288306
view.clearFocus();
289307
}
290308

291-
private void ensureValidAndroidVersion() {
292-
if (Build.VERSION.SDK_INT < MINIMAL_SDK) {
309+
private void ensureValidAndroidVersion(int minSdkVersion) {
310+
if (Build.VERSION.SDK_INT < minSdkVersion) {
293311
throw new IllegalStateException(
294312
"Trying to use platform views with API "
295313
+ Build.VERSION.SDK_INT
296314
+ ", required API level is: "
297-
+ MINIMAL_SDK);
315+
+ minSdkVersion);
298316
}
299317
}
300318
};
@@ -306,6 +324,9 @@ public PlatformViewsController() {
306324
contextToPlatformView = new HashMap<>();
307325
overlayLayerViews = new SparseArray<>();
308326
currentFrameUsedOverlayLayerIds = new HashSet<>();
327+
328+
platformViewRequests = new SparseArray<>();
329+
platformViews = new SparseArray<>();
309330
}
310331

311332
/**
@@ -565,13 +586,60 @@ private void initializeRootImageViewIfNeeded() {
565586
}
566587
}
567588

589+
private void initializePlatformViewIfNeeded(int viewId) {
590+
if (platformViews.get(viewId) != null) {
591+
return;
592+
}
593+
594+
PlatformViewsChannel.PlatformViewCreationRequest request = platformViewRequests.get(viewId);
595+
if (request == null) {
596+
throw new IllegalStateException(
597+
"Platform view hasn't been initialized from the platform view channel.");
598+
}
599+
600+
if (!validateDirection(request.direction)) {
601+
throw new IllegalStateException(
602+
"Trying to create a view with unknown direction value: "
603+
+ request.direction
604+
+ "(view id: "
605+
+ viewId
606+
+ ")");
607+
}
608+
609+
PlatformViewFactory factory = registry.getFactory(request.viewType);
610+
if (factory == null) {
611+
throw new IllegalStateException(
612+
"Trying to create a platform view of unregistered type: " + request.viewType);
613+
}
614+
615+
Object createParams = null;
616+
if (request.params != null) {
617+
createParams = factory.getCreateArgsCodec().decodeMessage(request.params);
618+
}
619+
620+
PlatformView platformView = factory.create(context, viewId, createParams);
621+
View view = platformView.getView();
622+
platformViews.put(viewId, view);
623+
624+
((FlutterView) flutterView).addView(view);
625+
}
626+
568627
public void onDisplayPlatformView(int viewId, int x, int y, int width, int height) {
569628
initializeRootImageViewIfNeeded();
570-
// TODO: Implement this method. https://github.com/flutter/flutter/issues/58288
629+
initializePlatformViewIfNeeded(viewId);
630+
631+
View platformView = platformViews.get(viewId);
632+
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams((int) width, (int) height);
633+
layoutParams.leftMargin = (int) x;
634+
layoutParams.topMargin = (int) y;
635+
platformView.setLayoutParams(layoutParams);
636+
platformView.setVisibility(View.VISIBLE);
637+
platformView.bringToFront();
571638
}
572639

573640
public void onDisplayOverlaySurface(int id, int x, int y, int width, int height) {
574641
initializeRootImageViewIfNeeded();
642+
575643
FlutterImageView overlayView = overlayLayerViews.get(id);
576644
if (overlayView.getParent() == null) {
577645
((FlutterView) flutterView).addView(overlayView);

0 commit comments

Comments
 (0)