44
44
public class PlatformViewsController implements PlatformViewsAccessibilityDelegate {
45
45
private static final String TAG = "PlatformViewsController" ;
46
46
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
-
51
47
private final PlatformViewRegistryImpl registry ;
52
48
53
49
// The context of the Activity or Fragment hosting the render target for the Flutter engine.
@@ -80,6 +76,9 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega
80
76
// it is associated with(e.g if a platform view creates other views in the same virtual display.
81
77
private final HashMap <Context , View > contextToPlatformView ;
82
78
79
+ private final SparseArray <PlatformViewsChannel .PlatformViewCreationRequest > platformViewRequests ;
80
+ private final SparseArray <View > platformViews ;
81
+
83
82
// Map of unique IDs to views that render overlay layers.
84
83
private final SparseArray <FlutterImageView > overlayLayerViews ;
85
84
@@ -92,14 +91,39 @@ public class PlatformViewsController implements PlatformViewsAccessibilityDelega
92
91
// Overlay layer IDs that were displayed since the start of the current frame.
93
92
private HashSet <Integer > currentFrameUsedOverlayLayerIds ;
94
93
94
+ // Platform view IDs that were displayed since the start of the current frame.
95
+ private HashSet <Integer > currentFrameUsedPlatformViewIds ;
96
+
95
97
private final PlatformViewsChannel .PlatformViewsHandler channelHandler =
96
98
new PlatformViewsChannel .PlatformViewsHandler () {
97
- @ TargetApi ( Build . VERSION_CODES . JELLY_BEAN_MR1 )
99
+
98
100
@ Override
99
- public long createPlatformView (
101
+ public void createAndroidViewForPlatformView (
100
102
@ 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
+ }
102
119
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 );
103
127
if (!validateDirection (request .direction )) {
104
128
throw new IllegalStateException (
105
129
"Trying to create a view with unknown direction value: "
@@ -171,9 +195,8 @@ public long createPlatformView(
171
195
}
172
196
173
197
@ Override
174
- public void disposePlatformView (int viewId ) {
175
- ensureValidAndroidVersion ();
176
-
198
+ public void disposeVirtualDisplayForPlatformView (int viewId ) {
199
+ ensureValidAndroidVersion (Build .VERSION_CODES .KITKAT_WATCH );
177
200
VirtualDisplayController vdController = vdControllers .get (viewId );
178
201
if (vdController == null ) {
179
202
throw new IllegalStateException (
@@ -193,7 +216,7 @@ public void disposePlatformView(int viewId) {
193
216
public void resizePlatformView (
194
217
@ NonNull PlatformViewsChannel .PlatformViewResizeRequest request ,
195
218
@ NonNull Runnable onComplete ) {
196
- ensureValidAndroidVersion ();
219
+ ensureValidAndroidVersion (Build . VERSION_CODES . KITKAT_WATCH );
197
220
198
221
final VirtualDisplayController vdController = vdControllers .get (request .viewId );
199
222
if (vdController == null ) {
@@ -224,8 +247,6 @@ public void run() {
224
247
225
248
@ Override
226
249
public void onTouch (@ NonNull PlatformViewsChannel .PlatformViewTouch touch ) {
227
- ensureValidAndroidVersion ();
228
-
229
250
float density = context .getResources ().getDisplayMetrics ().density ;
230
251
PointerProperties [] pointerProperties =
231
252
parsePointerPropertiesList (touch .rawPointerPropertiesList )
@@ -256,14 +277,13 @@ public void onTouch(@NonNull PlatformViewsChannel.PlatformViewTouch touch) {
256
277
touch .source ,
257
278
touch .flags );
258
279
280
+ ensureValidAndroidVersion (Build .VERSION_CODES .KITKAT_WATCH );
259
281
vdControllers .get (touch .viewId ).dispatchTouchEvent (event );
260
282
}
261
283
262
284
@ TargetApi (Build .VERSION_CODES .JELLY_BEAN_MR1 )
263
285
@ Override
264
286
public void setDirection (int viewId , int direction ) {
265
- ensureValidAndroidVersion ();
266
-
267
287
if (!validateDirection (direction )) {
268
288
throw new IllegalStateException (
269
289
"Trying to set unknown direction value: "
@@ -273,6 +293,7 @@ public void setDirection(int viewId, int direction) {
273
293
+ ")" );
274
294
}
275
295
296
+ ensureValidAndroidVersion (Build .VERSION_CODES .KITKAT_WATCH );
276
297
View view = vdControllers .get (viewId ).getView ();
277
298
if (view == null ) {
278
299
throw new IllegalStateException (
@@ -284,17 +305,18 @@ public void setDirection(int viewId, int direction) {
284
305
285
306
@ Override
286
307
public void clearFocus (int viewId ) {
308
+ ensureValidAndroidVersion (Build .VERSION_CODES .KITKAT_WATCH );
287
309
View view = vdControllers .get (viewId ).getView ();
288
310
view .clearFocus ();
289
311
}
290
312
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 ) {
293
315
throw new IllegalStateException (
294
316
"Trying to use platform views with API "
295
317
+ Build .VERSION .SDK_INT
296
318
+ ", required API level is: "
297
- + MINIMAL_SDK );
319
+ + minSdkVersion );
298
320
}
299
321
}
300
322
};
@@ -306,6 +328,10 @@ public PlatformViewsController() {
306
328
contextToPlatformView = new HashMap <>();
307
329
overlayLayerViews = new SparseArray <>();
308
330
currentFrameUsedOverlayLayerIds = new HashSet <>();
331
+ currentFrameUsedPlatformViewIds = new HashSet <>();
332
+
333
+ platformViewRequests = new SparseArray <>();
334
+ platformViews = new SparseArray <>();
309
335
}
310
336
311
337
/**
@@ -565,13 +591,61 @@ private void initializeRootImageViewIfNeeded() {
565
591
}
566
592
}
567
593
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
+
568
632
public void onDisplayPlatformView (int viewId , int x , int y , int width , int height ) {
569
633
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 );
571
644
}
572
645
573
646
public void onDisplayOverlaySurface (int id , int x , int y , int width , int height ) {
574
647
initializeRootImageViewIfNeeded ();
648
+
575
649
FlutterImageView overlayView = overlayLayerViews .get (id );
576
650
if (overlayView .getParent () == null ) {
577
651
((FlutterView ) flutterView ).addView (overlayView );
@@ -588,19 +662,32 @@ public void onDisplayOverlaySurface(int id, int x, int y, int width, int height)
588
662
589
663
public void onBeginFrame () {
590
664
currentFrameUsedOverlayLayerIds .clear ();
665
+ currentFrameUsedPlatformViewIds .clear ();
591
666
}
592
667
593
668
public void onEndFrame () {
669
+ // Hide overlay surfaces that aren't rendered in the current frame.
594
670
for (int i = 0 ; i < overlayLayerViews .size (); i ++) {
595
- int key = overlayLayerViews .keyAt (i );
671
+ int overlayId = overlayLayerViews .keyAt (i );
596
672
FlutterImageView overlayView = overlayLayerViews .valueAt (i );
597
- if (currentFrameUsedOverlayLayerIds .contains (key )) {
673
+ if (currentFrameUsedOverlayLayerIds .contains (overlayId )) {
598
674
overlayView .acquireLatestImage ();
599
675
} else {
600
676
overlayView .setVisibility (View .GONE );
601
677
}
602
678
}
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.
604
691
if (flutterViewConvertedToImageView ) {
605
692
((FlutterView ) flutterView ).acquireLatestImageViewFrame ();
606
693
}
0 commit comments