4444public 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
@@ -92,14 +91,39 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega
9291 // Overlay layer IDs that were displayed since the start of the current frame.
9392 private HashSet <Integer > currentFrameUsedOverlayLayerIds ;
9493
94+ // Platform view IDs that were displayed since the start of the current frame.
95+ private HashSet <Integer > currentFrameUsedPlatformViewIds ;
96+
9597 private final PlatformViewsChannel .PlatformViewsHandler channelHandler =
9698 new PlatformViewsChannel .PlatformViewsHandler () {
97- @ TargetApi ( Build . VERSION_CODES . JELLY_BEAN_MR1 )
99+
98100 @ Override
99- public long createPlatformView (
101+ public void createAndroidViewForPlatformView (
100102 @ NonNull PlatformViewsChannel .PlatformViewCreationRequest request ) {
101- ensureValidAndroidVersion ();
103+ // API level 19 is required for android.graphics.ImageReader.
104+ ensureValidAndroidVersion (Build .VERSION_CODES .KITKAT );
105+ platformViewRequests .put (request .viewId , request );
106+ }
107+
108+ @ Override
109+ public void disposeAndroidViewForPlatformView (int viewId ) {
110+ // Hybrid view.
111+ if (platformViewRequests .get (viewId ) != null ) {
112+ platformViewRequests .remove (viewId );
113+ }
114+ if (platformViews .get (viewId ) != null ) {
115+ ((FlutterView ) flutterView ).removeView (platformViews .get (viewId ));
116+ platformViews .remove (viewId );
117+ }
118+ }
102119
120+ @ TargetApi (Build .VERSION_CODES .JELLY_BEAN_MR1 )
121+ @ Override
122+ public long createVirtualDisplayForPlatformView (
123+ @ NonNull PlatformViewsChannel .PlatformViewCreationRequest request ) {
124+ // API level 20 is required for VirtualDisplay#setSurface which we use when resizing a
125+ // platform view.
126+ ensureValidAndroidVersion (Build .VERSION_CODES .KITKAT_WATCH );
103127 if (!validateDirection (request .direction )) {
104128 throw new IllegalStateException (
105129 "Trying to create a view with unknown direction value: "
@@ -171,9 +195,8 @@ public long createPlatformView(
171195 }
172196
173197 @ Override
174- public void disposePlatformView (int viewId ) {
175- ensureValidAndroidVersion ();
176-
198+ public void disposeVirtualDisplayForPlatformView (int viewId ) {
199+ ensureValidAndroidVersion (Build .VERSION_CODES .KITKAT_WATCH );
177200 VirtualDisplayController vdController = vdControllers .get (viewId );
178201 if (vdController == null ) {
179202 throw new IllegalStateException (
@@ -193,7 +216,7 @@ public void disposePlatformView(int viewId) {
193216 public void resizePlatformView (
194217 @ NonNull PlatformViewsChannel .PlatformViewResizeRequest request ,
195218 @ NonNull Runnable onComplete ) {
196- ensureValidAndroidVersion ();
219+ ensureValidAndroidVersion (Build . VERSION_CODES . KITKAT_WATCH );
197220
198221 final VirtualDisplayController vdController = vdControllers .get (request .viewId );
199222 if (vdController == null ) {
@@ -224,8 +247,6 @@ public void run() {
224247
225248 @ Override
226249 public void onTouch (@ NonNull PlatformViewsChannel .PlatformViewTouch touch ) {
227- ensureValidAndroidVersion ();
228-
229250 float density = context .getResources ().getDisplayMetrics ().density ;
230251 PointerProperties [] pointerProperties =
231252 parsePointerPropertiesList (touch .rawPointerPropertiesList )
@@ -256,14 +277,13 @@ public void onTouch(@NonNull PlatformViewsChannel.PlatformViewTouch touch) {
256277 touch .source ,
257278 touch .flags );
258279
280+ ensureValidAndroidVersion (Build .VERSION_CODES .KITKAT_WATCH );
259281 vdControllers .get (touch .viewId ).dispatchTouchEvent (event );
260282 }
261283
262284 @ TargetApi (Build .VERSION_CODES .JELLY_BEAN_MR1 )
263285 @ Override
264286 public void setDirection (int viewId , int direction ) {
265- ensureValidAndroidVersion ();
266-
267287 if (!validateDirection (direction )) {
268288 throw new IllegalStateException (
269289 "Trying to set unknown direction value: "
@@ -273,6 +293,7 @@ public void setDirection(int viewId, int direction) {
273293 + ")" );
274294 }
275295
296+ ensureValidAndroidVersion (Build .VERSION_CODES .KITKAT_WATCH );
276297 View view = vdControllers .get (viewId ).getView ();
277298 if (view == null ) {
278299 throw new IllegalStateException (
@@ -284,17 +305,18 @@ public void setDirection(int viewId, int direction) {
284305
285306 @ Override
286307 public void clearFocus (int viewId ) {
308+ ensureValidAndroidVersion (Build .VERSION_CODES .KITKAT_WATCH );
287309 View view = vdControllers .get (viewId ).getView ();
288310 view .clearFocus ();
289311 }
290312
291- private void ensureValidAndroidVersion () {
292- if (Build .VERSION .SDK_INT < MINIMAL_SDK ) {
313+ private void ensureValidAndroidVersion (int minSdkVersion ) {
314+ if (Build .VERSION .SDK_INT < minSdkVersion ) {
293315 throw new IllegalStateException (
294316 "Trying to use platform views with API "
295317 + Build .VERSION .SDK_INT
296318 + ", required API level is: "
297- + MINIMAL_SDK );
319+ + minSdkVersion );
298320 }
299321 }
300322 };
@@ -306,6 +328,10 @@ public PlatformViewsController() {
306328 contextToPlatformView = new HashMap <>();
307329 overlayLayerViews = new SparseArray <>();
308330 currentFrameUsedOverlayLayerIds = new HashSet <>();
331+ currentFrameUsedPlatformViewIds = new HashSet <>();
332+
333+ platformViewRequests = new SparseArray <>();
334+ platformViews = new SparseArray <>();
309335 }
310336
311337 /**
@@ -565,13 +591,61 @@ private void initializeRootImageViewIfNeeded() {
565591 }
566592 }
567593
594+ private void initializePlatformViewIfNeeded (int viewId ) {
595+ if (platformViews .get (viewId ) != null ) {
596+ return ;
597+ }
598+
599+ PlatformViewsChannel .PlatformViewCreationRequest request = platformViewRequests .get (viewId );
600+ if (request == null ) {
601+ throw new IllegalStateException (
602+ "Platform view hasn't been initialized from the platform view channel." );
603+ }
604+
605+ if (!validateDirection (request .direction )) {
606+ throw new IllegalStateException (
607+ "Trying to create a view with unknown direction value: "
608+ + request .direction
609+ + "(view id: "
610+ + viewId
611+ + ")" );
612+ }
613+
614+ PlatformViewFactory factory = registry .getFactory (request .viewType );
615+ if (factory == null ) {
616+ throw new IllegalStateException (
617+ "Trying to create a platform view of unregistered type: " + request .viewType );
618+ }
619+
620+ Object createParams = null ;
621+ if (request .params != null ) {
622+ createParams = factory .getCreateArgsCodec ().decodeMessage (request .params );
623+ }
624+
625+ PlatformView platformView = factory .create (context , viewId , createParams );
626+ View view = platformView .getView ();
627+ platformViews .put (viewId , view );
628+
629+ ((FlutterView ) flutterView ).addView (view );
630+ }
631+
568632 public void onDisplayPlatformView (int viewId , int x , int y , int width , int height ) {
569633 initializeRootImageViewIfNeeded ();
570- // TODO: Implement this method. https://github.com/flutter/flutter/issues/58288
634+ initializePlatformViewIfNeeded (viewId );
635+
636+ View platformView = platformViews .get (viewId );
637+ FrameLayout .LayoutParams layoutParams = new FrameLayout .LayoutParams ((int ) width , (int ) height );
638+ layoutParams .leftMargin = (int ) x ;
639+ layoutParams .topMargin = (int ) y ;
640+ platformView .setLayoutParams (layoutParams );
641+ platformView .setVisibility (View .VISIBLE );
642+ platformView .bringToFront ();
643+ currentFrameUsedPlatformViewIds .add (viewId );
571644 }
572645
573646 public void onDisplayOverlaySurface (int id , int x , int y , int width , int height ) {
574647 initializeRootImageViewIfNeeded ();
648+
575649 FlutterImageView overlayView = overlayLayerViews .get (id );
576650 if (overlayView .getParent () == null ) {
577651 ((FlutterView ) flutterView ).addView (overlayView );
@@ -588,19 +662,32 @@ public void onDisplayOverlaySurface(int id, int x, int y, int width, int height)
588662
589663 public void onBeginFrame () {
590664 currentFrameUsedOverlayLayerIds .clear ();
665+ currentFrameUsedPlatformViewIds .clear ();
591666 }
592667
593668 public void onEndFrame () {
669+ // Hide overlay surfaces that aren't rendered in the current frame.
594670 for (int i = 0 ; i < overlayLayerViews .size (); i ++) {
595- int key = overlayLayerViews .keyAt (i );
671+ int overlayId = overlayLayerViews .keyAt (i );
596672 FlutterImageView overlayView = overlayLayerViews .valueAt (i );
597- if (currentFrameUsedOverlayLayerIds .contains (key )) {
673+ if (currentFrameUsedOverlayLayerIds .contains (overlayId )) {
598674 overlayView .acquireLatestImage ();
599675 } else {
600676 overlayView .setVisibility (View .GONE );
601677 }
602678 }
603-
679+ // Hide platform views that aren't rendered in the current frame.
680+ // The platform view is destroyed by the framework after the widget is disposed.
681+ //
682+ // The framework diposes the platform view, when its `State` object will never
683+ // build again.
684+ for (int i = 0 ; i < platformViews .size (); i ++) {
685+ int viewId = platformViews .keyAt (i );
686+ if (!currentFrameUsedPlatformViewIds .contains (viewId )) {
687+ platformViews .get (viewId ).setVisibility (View .GONE );
688+ }
689+ }
690+ // If the background surface is still an image, then acquire the latest image.
604691 if (flutterViewConvertedToImageView ) {
605692 ((FlutterView ) flutterView ).acquireLatestImageViewFrame ();
606693 }
0 commit comments