Flutter Engine
The Flutter Engine
PlatformViewsControllerTest.java
Go to the documentation of this file.
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
5package io.flutter.plugin.platform;
6
7import static android.os.Looper.getMainLooper;
8import static io.flutter.embedding.engine.systemchannels.PlatformViewsChannel.PlatformViewTouch;
9import static org.junit.Assert.*;
10import static org.mockito.ArgumentMatchers.*;
11import static org.mockito.Mockito.*;
12import static org.robolectric.Shadows.shadowOf;
13
14import android.app.Presentation;
15import android.content.Context;
16import android.content.MutableContextWrapper;
17import android.content.res.AssetManager;
18import android.graphics.SurfaceTexture;
19import android.media.Image;
20import android.util.SparseArray;
21import android.view.MotionEvent;
22import android.view.Surface;
23import android.view.SurfaceHolder;
24import android.view.SurfaceView;
25import android.view.View;
26import android.view.ViewParent;
27import android.widget.FrameLayout;
28import android.widget.FrameLayout.LayoutParams;
29import androidx.annotation.NonNull;
30import androidx.test.core.app.ApplicationProvider;
31import androidx.test.ext.junit.runners.AndroidJUnit4;
32import io.flutter.embedding.android.FlutterImageView;
33import io.flutter.embedding.android.FlutterSurfaceView;
34import io.flutter.embedding.android.FlutterView;
35import io.flutter.embedding.android.MotionEventTracker;
36import io.flutter.embedding.engine.FlutterEngine;
37import io.flutter.embedding.engine.FlutterJNI;
38import io.flutter.embedding.engine.FlutterOverlaySurface;
39import io.flutter.embedding.engine.dart.DartExecutor;
40import io.flutter.embedding.engine.mutatorsstack.FlutterMutatorView;
41import io.flutter.embedding.engine.mutatorsstack.FlutterMutatorsStack;
42import io.flutter.embedding.engine.renderer.FlutterRenderer;
43import io.flutter.embedding.engine.systemchannels.AccessibilityChannel;
44import io.flutter.embedding.engine.systemchannels.MouseCursorChannel;
45import io.flutter.embedding.engine.systemchannels.PlatformViewsChannel;
46import io.flutter.embedding.engine.systemchannels.PlatformViewsChannel.PlatformViewTouch;
47import io.flutter.embedding.engine.systemchannels.SettingsChannel;
48import io.flutter.embedding.engine.systemchannels.TextInputChannel;
49import io.flutter.plugin.common.MethodCall;
50import io.flutter.plugin.common.StandardMessageCodec;
51import io.flutter.plugin.common.StandardMethodCodec;
52import io.flutter.plugin.localization.LocalizationPlugin;
53import io.flutter.view.TextureRegistry;
54import java.nio.ByteBuffer;
55import java.util.Arrays;
56import java.util.HashMap;
57import java.util.List;
58import java.util.Map;
59import org.junit.Ignore;
60import org.junit.Test;
61import org.junit.runner.RunWith;
62import org.mockito.ArgumentCaptor;
63import org.robolectric.annotation.Config;
64import org.robolectric.annotation.Implementation;
65import org.robolectric.annotation.Implements;
66import org.robolectric.shadows.ShadowDialog;
67import org.robolectric.shadows.ShadowSurfaceView;
68
69@Config(manifest = Config.NONE)
70@RunWith(AndroidJUnit4.class)
72 // An implementation of PlatformView that counts invocations of its lifecycle callbacks.
74 static final String VIEW_TYPE_ID = "CountingPlatformView";
75 private View view;
76
77 public CountingPlatformView(Context context) {
78 view = new SurfaceView(context);
79 }
80
81 public int disposeCalls = 0;
82 public int attachCalls = 0;
83 public int detachCalls = 0;
84
85 @Override
86 public void dispose() {
87 // We have been removed from the view hierarhy before the call to dispose.
88 assertNull(view.getParent());
89 disposeCalls++;
90 }
91
92 @Override
93 public View getView() {
94 return view;
95 }
96
97 @Override
98 public void onFlutterViewAttached(View flutterView) {
99 attachCalls++;
100 }
101
102 @Override
103 public void onFlutterViewDetached() {
104 detachCalls++;
105 }
106 }
107
108 @Test
109 @Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
111 PlatformViewsController platformViewsController = new PlatformViewsController();
112 FlutterJNI jni = new FlutterJNI();
113 attach(jni, platformViewsController);
114 // Get the platform view registry.
115 PlatformViewRegistry registry = platformViewsController.getRegistry();
116
117 // Register a factory for our platform view.
118 registry.registerViewFactory(
121 @Override
122 public PlatformView create(Context context, int viewId, Object args) {
123 return new CountingPlatformView(context);
124 }
125 });
126
127 // Create the platform view.
128 int viewId = 0;
129 final PlatformViewsChannel.PlatformViewCreationRequest request =
131 viewId,
132 CountingPlatformView.VIEW_TYPE_ID,
133 0,
134 0,
135 128,
136 128,
137 View.LAYOUT_DIRECTION_LTR,
138 null);
139 PlatformView pView = platformViewsController.createPlatformView(request, true);
140 assertTrue(pView instanceof CountingPlatformView);
141 CountingPlatformView cpv = (CountingPlatformView) pView;
142 platformViewsController.configureForTextureLayerComposition(pView, request);
143 assertEquals(0, cpv.disposeCalls);
144 platformViewsController.disposePlatformView(viewId);
145 assertEquals(1, cpv.disposeCalls);
146 }
147
148 @Test
149 @Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
151 PlatformViewsController platformViewsController = new PlatformViewsController();
152 FlutterJNI jni = new FlutterJNI();
153 attach(jni, platformViewsController);
154 // Get the platform view registry.
155 PlatformViewRegistry registry = platformViewsController.getRegistry();
156
157 // Register a factory for our platform view.
158 registry.registerViewFactory(
161 @Override
162 public PlatformView create(Context context, int viewId, Object args) {
163 return new CountingPlatformView(context);
164 }
165 });
166
167 // Create the platform view.
168 int viewId = 0;
169 final PlatformViewsChannel.PlatformViewCreationRequest request =
171 viewId,
172 CountingPlatformView.VIEW_TYPE_ID,
173 0,
174 0,
175 128,
176 128,
177 View.LAYOUT_DIRECTION_LTR,
178 null);
179 PlatformView pView = platformViewsController.createPlatformView(request, true);
180 assertTrue(pView instanceof CountingPlatformView);
181 CountingPlatformView cpv = (CountingPlatformView) pView;
182 assertEquals(1, cpv.attachCalls);
183 assertEquals(0, cpv.detachCalls);
184 assertEquals(0, cpv.disposeCalls);
185 platformViewsController.detachFromView();
186 assertEquals(1, cpv.attachCalls);
187 assertEquals(1, cpv.detachCalls);
188 assertEquals(0, cpv.disposeCalls);
189 platformViewsController.disposePlatformView(viewId);
190 }
191
192 @Ignore
193 @Test
195 // Setup test structure.
196 // Create a fake View that represents the View that renders a Flutter UI.
197 View fakeFlutterView = new View(ApplicationProvider.getApplicationContext());
198
199 // Create fake VirtualDisplayControllers. This requires internal knowledge of
200 // PlatformViewsController. We know that all PlatformViewsController does is
201 // forward view attachment/detachment calls to it's VirtualDisplayControllers.
202 //
203 // TODO(mattcarroll): once PlatformViewsController is refactored into testable
204 // pieces, remove this test and avoid verifying private behavior.
205 VirtualDisplayController fakeVdController1 = mock(VirtualDisplayController.class);
206
207 SingleViewPresentation presentation = fakeVdController1.presentation;
208
209 fakeVdController1.resize(10, 10, null);
210
211 assertEquals(fakeVdController1.presentation != presentation, true);
212 assertEquals(presentation.isShowing(), false);
213 }
214
215 @Test
216 @Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
218 final int platformViewId = 0;
219 FlutterView fakeFlutterView = new FlutterView(ApplicationProvider.getApplicationContext());
220 VirtualDisplayController fakeVdController = mock(VirtualDisplayController.class);
221 PlatformViewsController platformViewsController = new PlatformViewsController();
222 platformViewsController.vdControllers.put(platformViewId, fakeVdController);
223
224 platformViewsController.attachToView(fakeFlutterView);
225
226 FlutterJNI jni = new FlutterJNI();
227 attach(jni, platformViewsController);
228
229 resize(jni, platformViewsController, platformViewId, 10.0, 20.0);
230
231 ArgumentCaptor<Runnable> resizeCallbackCaptor = ArgumentCaptor.forClass(Runnable.class);
232 verify(fakeVdController, times(1)).resize(anyInt(), anyInt(), resizeCallbackCaptor.capture());
233
234 // Simulate a detach call before the resize completes.
235 platformViewsController.detach();
236
237 // Trigger the callback to ensure that it doesn't crash.
238 resizeCallbackCaptor.getValue().run();
239 }
240
241 @Test
242 @Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
244 final int platformViewId = 0;
245 FlutterView fakeFlutterView = new FlutterView(ApplicationProvider.getApplicationContext());
246 VirtualDisplayController fakeVdController = mock(VirtualDisplayController.class);
247 PlatformViewsController platformViewsController = new PlatformViewsController();
248 FlutterJNI jni = new FlutterJNI();
249 attach(jni, platformViewsController);
250 platformViewsController.attachToView(fakeFlutterView);
251
252 PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
253 PlatformView platformView = mock(PlatformView.class);
254 Context context = ApplicationProvider.getApplicationContext();
255 View androidView = new View(context);
256 when(platformView.getView()).thenReturn(androidView);
257 when(viewFactory.create(any(), eq(platformViewId), any())).thenReturn(platformView);
258 platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
259 createPlatformView(
260 jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ false);
261
262 platformViewsController.vdControllers.put(platformViewId, fakeVdController);
263
264 // Simulate dispose call from the framework.
265 disposePlatformView(jni, platformViewsController, platformViewId);
266
267 // Ensure VirtualDisplayController.dispose() is called
268 verify(fakeVdController, times(1)).dispose();
269 }
270
271 @Test
274 PlatformViewsController platformViewsController = new PlatformViewsController();
275
276 MotionEvent original =
277 MotionEvent.obtain(
278 100, // downTime
279 100, // eventTime
280 1, // action
281 0, // x
282 0, // y
283 0 // metaState
284 );
285
286 // track an event that will later get passed to us from framework
287 MotionEventTracker.MotionEventId motionEventId = motionEventTracker.track(original);
288
289 PlatformViewTouch frameWorkTouch =
291 0, // viewId
292 original.getDownTime(),
293 original.getEventTime(),
294 2, // action
295 1, // pointerCount
296 Arrays.asList(Arrays.asList(0, 0)), // pointer properties
297 Arrays.asList(Arrays.asList(0., 1., 2., 3., 4., 5., 6., 7., 8.)), // pointer coords
298 original.getMetaState(),
299 original.getButtonState(),
300 original.getXPrecision(),
301 original.getYPrecision(),
302 original.getDeviceId(),
303 original.getEdgeFlags(),
304 original.getSource(),
305 original.getFlags(),
306 motionEventId.getId());
307
308 MotionEvent resolvedEvent =
309 platformViewsController.toMotionEvent(
310 1, // density
311 frameWorkTouch,
312 true // usingVirtualDisplays
313 );
314
315 assertEquals(resolvedEvent.getAction(), frameWorkTouch.action);
316 assertNotEquals(resolvedEvent.getAction(), original.getAction());
317 }
318
319 @Test
322 PlatformViewsController platformViewsController = new PlatformViewsController();
323
324 MotionEvent original =
325 MotionEvent.obtain(
326 10, // downTime
327 10, // eventTime
328 261, // action
329 0, // x
330 0, // y
331 0 // metaState
332 );
333
334 MotionEventTracker.MotionEventId motionEventId = motionEventTracker.track(original);
335
336 PlatformViewTouch frameWorkTouch =
338 0, // viewId
339 original.getDownTime(),
340 original.getEventTime(),
341 0, // action
342 1, // pointerCount
343 Arrays.asList(Arrays.asList(0, 0)), // pointer properties
344 Arrays.asList(Arrays.asList(0., 1., 2., 3., 4., 5., 6., 7., 8.)), // pointer coords
345 original.getMetaState(),
346 original.getButtonState(),
347 original.getXPrecision(),
348 original.getYPrecision(),
349 original.getDeviceId(),
350 original.getEdgeFlags(),
351 original.getSource(),
352 original.getFlags(),
353 motionEventId.getId());
354 MotionEvent resolvedEvent =
355 platformViewsController.toMotionEvent(
356 1, // density
357 frameWorkTouch,
358 false // usingVirtualDisplays
359 );
360 assertEquals(resolvedEvent.getAction(), original.getAction());
361 assertNotEquals(resolvedEvent.getAction(), frameWorkTouch.action);
362 }
363
364 private MotionEvent makePlatformViewTouchAndInvokeToMotionEvent(
365 PlatformViewsController platformViewsController,
366 MotionEventTracker motionEventTracker,
367 MotionEvent original,
368 boolean usingVirtualDisplays) {
369 MotionEventTracker.MotionEventId motionEventId = motionEventTracker.track(original);
370
371 // Construct a PlatformViewTouch.rawPointerPropertiesList by doing the inverse of
372 // PlatformViewsController.parsePointerPropertiesList.
373 List<List<Integer>> pointerProperties =
374 Arrays.asList(Arrays.asList(original.getPointerId(0), original.getToolType(0)));
375 // Construct a PlatformViewTouch.rawPointerCoords by doing the inverse of
376 // PlatformViewsController.parsePointerCoordsList.
377 List<List<Double>> pointerCoordinates =
378 Arrays.asList(
379 Arrays.asList(
380 (double) original.getOrientation(),
381 (double) original.getPressure(),
382 (double) original.getSize(),
383 (double) original.getToolMajor(),
384 (double) original.getToolMinor(),
385 (double) original.getTouchMajor(),
386 (double) original.getTouchMinor(),
387 (double) original.getX(),
388 (double) original.getY()));
389 // Make a platform view touch from the motion event.
390 PlatformViewTouch frameWorkTouchNonVd =
392 0, // viewId
393 original.getDownTime(),
394 original.getEventTime(),
395 original.getAction(),
396 1, // pointerCount
397 pointerProperties, // pointer properties
398 pointerCoordinates, // pointer coords
399 original.getMetaState(),
400 original.getButtonState(),
401 original.getXPrecision(),
402 original.getYPrecision(),
403 original.getDeviceId(),
404 original.getEdgeFlags(),
405 original.getSource(),
406 original.getFlags(),
407 motionEventId.getId());
408
409 return platformViewsController.toMotionEvent(
410 1, // density
411 frameWorkTouchNonVd,
412 usingVirtualDisplays);
413 }
414
415 @Test
418 PlatformViewsController platformViewsController = new PlatformViewsController();
419
420 MotionEvent original =
421 MotionEvent.obtain(
422 10, // downTime
423 10, // eventTime
424 261, // action
425 1, // x
426 1, // y
427 0 // metaState
428 );
429
430 MotionEvent resolvedNonVdEvent =
431 makePlatformViewTouchAndInvokeToMotionEvent(
432 platformViewsController, motionEventTracker, original, false);
433
434 MotionEvent resolvedVdEvent =
435 makePlatformViewTouchAndInvokeToMotionEvent(
436 platformViewsController, motionEventTracker, original, true);
437
438 assertEquals(resolvedVdEvent.getEventTime(), resolvedNonVdEvent.getEventTime());
439 assertEquals(resolvedVdEvent.getX(), resolvedNonVdEvent.getX(), 0.001f);
440 assertEquals(resolvedVdEvent.getY(), resolvedNonVdEvent.getY(), 0.001f);
441 }
442
443 @Test
444 @Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
446 PlatformViewsController platformViewsController = new PlatformViewsController();
447
448 int platformViewId = 0;
449 assertNull(platformViewsController.getPlatformViewById(platformViewId));
450
451 PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
452 PlatformView platformView = mock(PlatformView.class);
453 View androidView = mock(View.class);
454 when(platformView.getView()).thenReturn(androidView);
455 when(viewFactory.create(any(), eq(platformViewId), any())).thenReturn(platformView);
456 platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
457
458 FlutterJNI jni = new FlutterJNI();
459 attach(jni, platformViewsController);
460
461 // Simulate create call from the framework.
462 createPlatformView(jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ true);
463
464 platformViewsController.initializePlatformViewIfNeeded(platformViewId);
465
466 View resultAndroidView = platformViewsController.getPlatformViewById(platformViewId);
467 assertNotNull(resultAndroidView);
468 assertEquals(resultAndroidView, androidView);
469 }
470
471 @Test
472 @Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
474 PlatformViewsController platformViewsController = new PlatformViewsController();
475
476 int platformViewId = 0;
477 assertNull(platformViewsController.getPlatformViewById(platformViewId));
478
479 PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
480 PlatformView platformView = mock(PlatformView.class);
481 when(platformView.getView()).thenReturn(mock(View.class));
482 when(viewFactory.create(any(), eq(platformViewId), any())).thenReturn(platformView);
483 platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
484
485 FlutterJNI jni = new FlutterJNI();
486 attach(jni, platformViewsController);
487
488 // Simulate create call from the framework.
489 createPlatformView(jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ true);
490 verify(viewFactory, times(1)).create(any(), eq(platformViewId), any());
491 }
492
493 @Test
494 @Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
496 PlatformViewsController platformViewsController = new PlatformViewsController();
497
498 int platformViewId = 0;
499 assertNull(platformViewsController.getPlatformViewById(platformViewId));
500
501 PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
502 PlatformView platformView = mock(PlatformView.class);
503 when(platformView.getView()).thenReturn(mock(View.class));
504 ArgumentCaptor<Context> passedContext = ArgumentCaptor.forClass(Context.class);
505 when(viewFactory.create(passedContext.capture(), eq(platformViewId), any()))
506 .thenReturn(platformView);
507 platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
508
509 FlutterJNI jni = new FlutterJNI();
510 attach(jni, platformViewsController);
511
512 // Simulate create call from the framework.
513 createPlatformView(
514 jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ false);
515 assertTrue(passedContext.getValue() instanceof MutableContextWrapper);
516 }
517
518 @Test
519 @Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
521 PlatformViewsController platformViewsController = new PlatformViewsController();
522
523 int platformViewId = 0;
524 assertNull(platformViewsController.getPlatformViewById(platformViewId));
525
526 PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
527 PlatformView platformView = mock(PlatformView.class);
528 when(platformView.getView()).thenReturn(mock(View.class));
529 ArgumentCaptor<Context> passedContext = ArgumentCaptor.forClass(Context.class);
530 when(viewFactory.create(passedContext.capture(), eq(platformViewId), any()))
531 .thenReturn(platformView);
532 platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
533
534 FlutterJNI jni = new FlutterJNI();
535 attach(jni, platformViewsController);
536
537 // Simulate create call from the framework.
538 createPlatformView(jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ true);
539 assertFalse(passedContext.getValue() instanceof MutableContextWrapper);
540 }
541
542 @Test
543 @Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
545 PlatformViewsController platformViewsController = new PlatformViewsController();
546 platformViewsController.setSoftwareRendering(true);
547
548 int platformViewId = 0;
549 assertNull(platformViewsController.getPlatformViewById(platformViewId));
550
551 PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
552 PlatformView platformView = mock(PlatformView.class);
553
554 View androidView = mock(View.class);
555 when(platformView.getView()).thenReturn(androidView);
556 when(viewFactory.create(any(), eq(platformViewId), any())).thenReturn(platformView);
557 platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
558
559 FlutterJNI jni = new FlutterJNI();
560 attach(jni, platformViewsController);
561
562 // Simulate create call from the framework.
563 createPlatformView(
564 jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ false);
565 verify(androidView, times(1)).setLayoutDirection(0);
566 }
567
568 @Test
569 @Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
571 PlatformViewsController platformViewsController = new PlatformViewsController();
572 platformViewsController.setSoftwareRendering(true);
573
574 int platformViewId = 0;
575 assertNull(platformViewsController.getPlatformViewById(platformViewId));
576
577 PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
578 PlatformView platformView = mock(PlatformView.class);
579
580 View androidView = mock(View.class);
581 when(platformView.getView()).thenReturn(androidView);
582 when(viewFactory.create(any(), eq(platformViewId), any())).thenReturn(platformView);
583 platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
584
585 FlutterJNI jni = new FlutterJNI();
586 attach(jni, platformViewsController);
587
588 // Simulate create call from the framework.
589 createPlatformView(
590 jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ false);
591
592 ArgumentCaptor<FrameLayout.LayoutParams> layoutParamsCaptor =
593 ArgumentCaptor.forClass(FrameLayout.LayoutParams.class);
594 verify(androidView, times(2)).setLayoutParams(layoutParamsCaptor.capture());
595
596 List<FrameLayout.LayoutParams> capturedLayoutParams = layoutParamsCaptor.getAllValues();
597 assertEquals(capturedLayoutParams.get(0).width, 1);
598 assertEquals(capturedLayoutParams.get(0).height, 1);
599 }
600
601 @Test
602 @Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
604 PlatformViewsController platformViewsController = new PlatformViewsController();
605 platformViewsController.setSoftwareRendering(true);
606
607 int platformViewId = 0;
608 assertNull(platformViewsController.getPlatformViewById(platformViewId));
609
610 PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
611 PlatformView platformView = mock(PlatformView.class);
612
613 View androidView = mock(View.class);
614 when(platformView.getView()).thenReturn(androidView);
615 when(viewFactory.create(any(), eq(platformViewId), any())).thenReturn(platformView);
616 platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
617
618 FlutterJNI jni = new FlutterJNI();
619 attach(jni, platformViewsController);
620
621 // Simulate create call from the framework.
622 createPlatformView(
623 jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ false);
624 verify(androidView, times(1))
625 .setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
626 }
627
628 @Test
629 @Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
631 PlatformViewsController platformViewsController = new PlatformViewsController();
632
633 int platformViewId = 0;
634 assertNull(platformViewsController.getPlatformViewById(platformViewId));
635
636 PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
637 PlatformView platformView = mock(PlatformView.class);
638 when(platformView.getView()).thenReturn(null);
639 when(viewFactory.create(any(), eq(platformViewId), any())).thenReturn(platformView);
640 platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
641
642 FlutterJNI jni = new FlutterJNI();
643 attach(jni, platformViewsController);
644
645 // Simulate create call from the framework.
646 createPlatformView(
647 jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ false);
648 assertEquals(ShadowFlutterJNI.getResponses().size(), 1);
649
650 assertThrows(
651 IllegalStateException.class,
652 () -> {
653 platformViewsController.initializePlatformViewIfNeeded(platformViewId);
654 });
655 }
656
657 @Test
658 @Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
660 PlatformViewsController platformViewsController = new PlatformViewsController();
661
662 int platformViewId = 0;
663 assertNull(platformViewsController.getPlatformViewById(platformViewId));
664
665 PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
666 PlatformView platformView = mock(PlatformView.class);
667 when(platformView.getView()).thenReturn(null);
668 when(viewFactory.create(any(), eq(platformViewId), any())).thenReturn(platformView);
669 platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
670
671 FlutterJNI jni = new FlutterJNI();
672 attach(jni, platformViewsController);
673
674 // Simulate create call from the framework.
675 createPlatformView(jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ true);
676 assertEquals(ShadowFlutterJNI.getResponses().size(), 1);
677
678 assertThrows(
679 IllegalStateException.class,
680 () -> {
681 platformViewsController.initializePlatformViewIfNeeded(platformViewId);
682 });
683 }
684
685 @Test
686 @Config(
687 shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class, ShadowPresentation.class})
689 PlatformViewsController platformViewsController = new PlatformViewsController();
690
691 int platformViewId = 0;
692 assertNull(platformViewsController.getPlatformViewById(platformViewId));
693
694 PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
695 PlatformView platformView = mock(PlatformView.class);
696
697 SurfaceView pv = mock(SurfaceView.class);
698 when(pv.getContext()).thenReturn(mock(MutableContextWrapper.class));
699 when(pv.getLayoutParams()).thenReturn(new LayoutParams(1, 1));
700
701 when(platformView.getView()).thenReturn(pv);
702 when(viewFactory.create(any(), eq(platformViewId), any())).thenReturn(platformView);
703 platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
704
705 FlutterJNI jni = new FlutterJNI();
706 attach(jni, platformViewsController);
707
708 // Simulate create call from the framework.
709 createPlatformView(
710 jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ false);
711
712 assertFalse(platformViewsController.contextToEmbeddedView.isEmpty());
713 platformViewsController.onDetachedFromJNI();
714 assertTrue(platformViewsController.contextToEmbeddedView.isEmpty());
715 }
716
717 @Test
718 @Config(
719 shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class, ShadowPresentation.class})
721 PlatformViewsController platformViewsController = new PlatformViewsController();
722
723 int platformViewId = 0;
724 assertNull(platformViewsController.getPlatformViewById(platformViewId));
725
726 PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
727 PlatformView platformView = mock(PlatformView.class);
728
729 SurfaceView pv = mock(SurfaceView.class);
730 when(pv.getContext()).thenReturn(mock(MutableContextWrapper.class));
731 when(pv.getLayoutParams()).thenReturn(new LayoutParams(1, 1));
732
733 when(platformView.getView()).thenReturn(pv);
734 when(viewFactory.create(any(), eq(platformViewId), any())).thenReturn(platformView);
735 platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
736
737 FlutterJNI jni = new FlutterJNI();
738 attach(jni, platformViewsController);
739
740 // Simulate create call from the framework.
741 createPlatformView(
742 jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ false);
743
744 assertFalse(platformViewsController.contextToEmbeddedView.isEmpty());
745 platformViewsController.onDetachedFromJNI();
746 assertTrue(platformViewsController.contextToEmbeddedView.isEmpty());
747 }
748
749 @Test
750 @Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
752 PlatformViewsController platformViewsController = new PlatformViewsController();
753
754 int platformViewId = 0;
755 assertNull(platformViewsController.getPlatformViewById(platformViewId));
756
757 PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
758 PlatformView platformView = mock(PlatformView.class);
759 View androidView = mock(View.class);
760 when(androidView.getParent()).thenReturn(mock(ViewParent.class));
761 when(platformView.getView()).thenReturn(androidView);
762 when(viewFactory.create(any(), eq(platformViewId), any())).thenReturn(platformView);
763 platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
764
765 FlutterJNI jni = new FlutterJNI();
766 attach(jni, platformViewsController);
767
768 // Simulate create call from the framework.
769 createPlatformView(
770 jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ false);
771 assertEquals(ShadowFlutterJNI.getResponses().size(), 1);
772
773 assertThrows(
774 IllegalStateException.class,
775 () -> {
776 platformViewsController.initializePlatformViewIfNeeded(platformViewId);
777 });
778 }
779
780 @Test
781 @Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
783 PlatformViewsController platformViewsController = new PlatformViewsController();
784
785 int platformViewId = 0;
786 assertNull(platformViewsController.getPlatformViewById(platformViewId));
787
788 PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
789 PlatformView platformView = mock(PlatformView.class);
790 View androidView = mock(View.class);
791 when(androidView.getParent()).thenReturn(mock(ViewParent.class));
792 when(platformView.getView()).thenReturn(androidView);
793 when(viewFactory.create(any(), eq(platformViewId), any())).thenReturn(platformView);
794 platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
795
796 FlutterJNI jni = new FlutterJNI();
797 attach(jni, platformViewsController);
798
799 // Simulate create call from the framework.
800 createPlatformView(jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ true);
801 assertEquals(ShadowFlutterJNI.getResponses().size(), 1);
802
803 assertThrows(
804 IllegalStateException.class,
805 () -> {
806 platformViewsController.initializePlatformViewIfNeeded(platformViewId);
807 });
808 }
809
810 @Test
811 @Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
813 PlatformViewsController platformViewsController = new PlatformViewsController();
814
815 int platformViewId = 0;
816 assertNull(platformViewsController.getPlatformViewById(platformViewId));
817
818 PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
819 PlatformView platformView = mock(PlatformView.class);
820 final View androidView = mock(View.class);
821 when(platformView.getView()).thenReturn(androidView);
822 when(viewFactory.create(any(), eq(platformViewId), any())).thenReturn(platformView);
823 platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
824
825 FlutterJNI jni = new FlutterJNI();
826 attach(jni, platformViewsController);
827
828 verify(androidView, never()).setLayoutDirection(anyInt());
829
830 // Simulate create call from the framework.
831 createPlatformView(jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ true);
832 assertEquals(ShadowFlutterJNI.getResponses().size(), 1);
833
834 // Simulate set direction call from the framework.
835 setLayoutDirection(jni, platformViewsController, platformViewId, 1);
836 verify(androidView, times(1)).setLayoutDirection(1);
837
838 // The limit value of reply message will be equal to 2 if the layout direction is set
839 // successfully, otherwise it will be much more than 2 due to the reply message contains
840 // an error message wrapped with exception detail information.
841 assertEquals(ShadowFlutterJNI.getResponses().get(0).limit(), 2);
842 }
843
844 @Test
845 @Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
846 public void resizeAndroidView() {
847 PlatformViewsController platformViewsController = new PlatformViewsController();
848 platformViewsController.setSoftwareRendering(true);
849
850 int platformViewId = 0;
851 assertNull(platformViewsController.getPlatformViewById(platformViewId));
852
853 PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
854 PlatformView platformView = mock(PlatformView.class);
855 final View androidView = mock(View.class);
856 when(platformView.getView()).thenReturn(androidView);
857 when(viewFactory.create(any(), eq(platformViewId), any())).thenReturn(platformView);
858 platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
859
860 FlutterJNI jni = new FlutterJNI();
861 attach(jni, platformViewsController);
862
863 // Simulate create call from the framework.
864 createPlatformView(
865 jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ false);
866
867 reset(androidView);
868 when(androidView.getLayoutParams()).thenReturn(new FrameLayout.LayoutParams(0, 0));
869
870 // Simulate a resize call from the framework.
871 resize(jni, platformViewsController, platformViewId, 10.0, 20.0);
872
873 ArgumentCaptor<FrameLayout.LayoutParams> layoutParamsCaptor =
874 ArgumentCaptor.forClass(FrameLayout.LayoutParams.class);
875 verify(androidView, times(1)).setLayoutParams(layoutParamsCaptor.capture());
876
877 assertEquals(layoutParamsCaptor.getValue().width, 10);
878 assertEquals(layoutParamsCaptor.getValue().height, 20);
879 }
880
881 @Test
882 @Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
884 PlatformViewsController platformViewsController = new PlatformViewsController();
885
886 int platformViewId = 0;
887 assertNull(platformViewsController.getPlatformViewById(platformViewId));
888
889 PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
890 PlatformView platformView = mock(PlatformView.class);
891
892 Context context = ApplicationProvider.getApplicationContext();
893 View androidView = new View(context);
894
895 when(platformView.getView()).thenReturn(androidView);
896 when(viewFactory.create(any(), eq(platformViewId), any())).thenReturn(platformView);
897 platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
898
899 FlutterJNI jni = new FlutterJNI();
900 attach(jni, platformViewsController);
901
902 // Simulate create call from the framework.
903 createPlatformView(jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ true);
904 platformViewsController.initializePlatformViewIfNeeded(platformViewId);
905
906 assertNotNull(androidView.getParent());
907 assertTrue(androidView.getParent() instanceof FlutterMutatorView);
908
909 // Simulate dispose call from the framework.
910 disposePlatformView(jni, platformViewsController, platformViewId);
911 assertNull(androidView.getParent());
912
913 // Simulate create call from the framework.
914 createPlatformView(jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ true);
915 platformViewsController.initializePlatformViewIfNeeded(platformViewId);
916
917 assertNotNull(androidView.getParent());
918 assertTrue(androidView.getParent() instanceof FlutterMutatorView);
919 verify(platformView, times(1)).dispose();
920 }
921
922 @Test
923 @Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
925 PlatformViewsController platformViewsController = new PlatformViewsController();
926
927 int platformViewId = 0;
928 assertNull(platformViewsController.getPlatformViewById(platformViewId));
929
930 PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
931 PlatformView platformView = mock(PlatformView.class);
932
933 View androidView = mock(View.class);
934 when(platformView.getView()).thenReturn(androidView);
935 when(viewFactory.create(any(), eq(platformViewId), any())).thenReturn(platformView);
936 platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
937
938 FlutterJNI jni = new FlutterJNI();
939 attach(jni, platformViewsController);
940
941 // Simulate create call from the framework.
942 createPlatformView(
943 jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ false);
944 platformViewsController.initializePlatformViewIfNeeded(platformViewId);
945
946 when(platformView.getView()).thenReturn(null);
947
948 // Simulate dispose call from the framework.
949 disposePlatformView(jni, platformViewsController, platformViewId);
950 verify(platformView, times(1)).dispose();
951 }
952
953 @Test
954 @Config(
955 shadows = {
956 ShadowFlutterSurfaceView.class,
957 ShadowFlutterJNI.class,
958 ShadowPlatformTaskQueue.class
959 })
961 final PlatformViewsController platformViewsController = new PlatformViewsController();
962
963 final int platformViewId = 0;
964 assertNull(platformViewsController.getPlatformViewById(platformViewId));
965
966 final PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
967 final PlatformView platformView = mock(PlatformView.class);
968 when(platformView.getView()).thenReturn(mock(View.class));
969 when(viewFactory.create(any(), eq(platformViewId), any())).thenReturn(platformView);
970
971 platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
972
973 final FlutterJNI jni = new FlutterJNI();
974 jni.attachToNative();
975 attach(jni, platformViewsController);
976
977 jni.onFirstFrame();
978
979 // Simulate create call from the framework.
980 createPlatformView(jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ true);
981
982 // Produce a frame that displays a platform view and an overlay surface.
983 platformViewsController.onBeginFrame();
984 platformViewsController.onDisplayPlatformView(
985 platformViewId,
986 /* x=*/ 0,
987 /* y=*/ 0,
988 /* width=*/ 10,
989 /* height=*/ 10,
990 /* viewWidth=*/ 10,
991 /* viewHeight=*/ 10,
992 /* mutatorsStack=*/ new FlutterMutatorsStack());
993
994 final PlatformOverlayView overlayImageView = mock(PlatformOverlayView.class);
995 when(overlayImageView.acquireLatestImage()).thenReturn(true);
996
997 final FlutterOverlaySurface overlaySurface =
998 platformViewsController.createOverlaySurface(overlayImageView);
999 platformViewsController.onDisplayOverlaySurface(
1000 overlaySurface.getId(), /* x=*/ 0, /* y=*/ 0, /* width=*/ 10, /* height=*/ 10);
1001
1002 platformViewsController.onEndFrame();
1003
1004 // Simulate first frame from the framework.
1005 jni.onFirstFrame();
1006
1007 verify(overlayImageView, never()).detachFromRenderer();
1008
1009 // Produce a frame that doesn't display platform views.
1010 platformViewsController.onBeginFrame();
1011 platformViewsController.onEndFrame();
1012
1013 shadowOf(getMainLooper()).idle();
1014 verify(overlayImageView, times(1)).detachFromRenderer();
1015 }
1016
1017 @Test
1018 @Config(shadows = {ShadowFlutterSurfaceView.class, ShadowFlutterJNI.class})
1020 final PlatformViewsController platformViewsController = new PlatformViewsController();
1021
1022 final int platformViewId = 0;
1023 assertNull(platformViewsController.getPlatformViewById(platformViewId));
1024
1025 final PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
1026 final PlatformView platformView = mock(PlatformView.class);
1027 final View androidView = mock(View.class);
1028 when(platformView.getView()).thenReturn(androidView);
1029 when(viewFactory.create(any(), eq(platformViewId), any())).thenReturn(platformView);
1030
1031 platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
1032
1033 final FlutterJNI jni = new FlutterJNI();
1034 jni.attachToNative();
1035 attach(jni, platformViewsController);
1036
1037 jni.onFirstFrame();
1038
1039 // Simulate create call from the framework.
1040 createPlatformView(jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ true);
1041
1042 // Simulate first frame from the framework.
1043 jni.onFirstFrame();
1044 platformViewsController.onBeginFrame();
1045
1046 platformViewsController.onEndFrame();
1047 verify(androidView, never()).setVisibility(View.GONE);
1048
1049 final ViewParent parentView = mock(ViewParent.class);
1050 when(androidView.getParent()).thenReturn(parentView);
1051 }
1052
1053 @Test
1054 @Config(
1055 shadows = {
1056 ShadowFlutterSurfaceView.class,
1057 ShadowFlutterJNI.class,
1058 ShadowPlatformTaskQueue.class
1059 })
1061 final PlatformViewsController platformViewsController = new PlatformViewsController();
1062
1063 final int platformViewId = 0;
1064 assertNull(platformViewsController.getPlatformViewById(platformViewId));
1065
1066 final PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
1067 final PlatformView platformView = mock(PlatformView.class);
1068 final View androidView = mock(View.class);
1069 when(platformView.getView()).thenReturn(androidView);
1070 when(viewFactory.create(any(), eq(platformViewId), any())).thenReturn(platformView);
1071
1072 platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
1073
1074 final FlutterJNI jni = new FlutterJNI();
1075 jni.attachToNative();
1076
1077 final FlutterView flutterView = attach(jni, platformViewsController);
1078
1079 jni.onFirstFrame();
1080
1081 // Simulate create call from the framework.
1082 createPlatformView(jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ true);
1083 platformViewsController.initializePlatformViewIfNeeded(platformViewId);
1084 assertEquals(flutterView.getChildCount(), 2);
1085
1086 // Simulate first frame from the framework.
1087 jni.onFirstFrame();
1088 platformViewsController.onBeginFrame();
1089 platformViewsController.onEndFrame();
1090
1091 // Simulate dispose call from the framework.
1092 disposePlatformView(jni, platformViewsController, platformViewId);
1093 assertEquals(flutterView.getChildCount(), 1);
1094 }
1095
1096 @Test
1097 @Config(
1098 shadows = {
1099 ShadowFlutterSurfaceView.class,
1100 ShadowFlutterJNI.class,
1101 ShadowPlatformTaskQueue.class
1102 })
1104 final PlatformViewsController platformViewsController = new PlatformViewsController();
1105
1106 final int platformViewId = 0;
1107 assertNull(platformViewsController.getPlatformViewById(platformViewId));
1108
1109 final PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
1110 final PlatformView platformView = mock(PlatformView.class);
1111 when(platformView.getView()).thenReturn(mock(View.class));
1112 when(viewFactory.create(any(), eq(platformViewId), any())).thenReturn(platformView);
1113
1114 platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
1115
1116 final FlutterJNI jni = new FlutterJNI();
1117 jni.attachToNative();
1118 attach(jni, platformViewsController);
1119
1120 jni.onFirstFrame();
1121
1122 // Simulate create call from the framework.
1123 createPlatformView(jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ true);
1124
1125 // Produce a frame that displays a platform view and an overlay surface.
1126 platformViewsController.onBeginFrame();
1127 platformViewsController.onDisplayPlatformView(
1128 platformViewId,
1129 /* x=*/ 0,
1130 /* y=*/ 0,
1131 /* width=*/ 10,
1132 /* height=*/ 10,
1133 /* viewWidth=*/ 10,
1134 /* viewHeight=*/ 10,
1135 /* mutatorsStack=*/ new FlutterMutatorsStack());
1136
1137 final PlatformOverlayView overlayImageView = mock(PlatformOverlayView.class);
1138 when(overlayImageView.acquireLatestImage()).thenReturn(true);
1139
1140 final FlutterOverlaySurface overlaySurface =
1141 platformViewsController.createOverlaySurface(overlayImageView);
1142 // This is OK.
1143 platformViewsController.onDisplayOverlaySurface(
1144 overlaySurface.getId(), /* x=*/ 0, /* y=*/ 0, /* width=*/ 10, /* height=*/ 10);
1145
1146 platformViewsController.detach();
1147
1148 verify(overlayImageView, times(1)).closeImageReader();
1149 verify(overlayImageView, times(1)).detachFromRenderer();
1150 }
1151
1152 @Test
1153 @Config(shadows = {ShadowFlutterSurfaceView.class, ShadowFlutterJNI.class})
1155 final PlatformViewsController platformViewsController = new PlatformViewsController();
1156
1157 final int platformViewId = 0;
1158 assertNull(platformViewsController.getPlatformViewById(platformViewId));
1159
1160 final PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
1161 final PlatformView platformView = mock(PlatformView.class);
1162 when(platformView.getView()).thenReturn(mock(View.class));
1163 when(viewFactory.create(any(), eq(platformViewId), any())).thenReturn(platformView);
1164
1165 platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
1166
1167 final FlutterJNI jni = new FlutterJNI();
1168 jni.attachToNative();
1169 attach(jni, platformViewsController);
1170
1171 final FlutterView flutterView = mock(FlutterView.class);
1172 platformViewsController.attachToView(flutterView);
1173
1174 final PlatformOverlayView overlayImageView = mock(PlatformOverlayView.class);
1175 when(overlayImageView.acquireLatestImage()).thenReturn(true);
1176
1177 final FlutterOverlaySurface overlaySurface =
1178 platformViewsController.createOverlaySurface(overlayImageView);
1179
1180 platformViewsController.onDisplayOverlaySurface(
1181 overlaySurface.getId(), /* x=*/ 0, /* y=*/ 0, /* width=*/ 10, /* height=*/ 10);
1182
1183 platformViewsController.detachFromView();
1184
1185 verify(overlayImageView, times(1)).closeImageReader();
1186 verify(overlayImageView, times(1)).detachFromRenderer();
1187 verify(flutterView, times(1)).removeView(overlayImageView);
1188 }
1189
1190 @Test
1191 @Config(shadows = {ShadowFlutterSurfaceView.class, ShadowFlutterJNI.class})
1193 final PlatformViewsController platformViewsController = new PlatformViewsController();
1194
1195 final int platformViewId = 0;
1196 assertNull(platformViewsController.getPlatformViewById(platformViewId));
1197
1198 final PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
1199 final PlatformView platformView = mock(PlatformView.class);
1200 when(platformView.getView()).thenReturn(mock(View.class));
1201 when(viewFactory.create(any(), eq(platformViewId), any())).thenReturn(platformView);
1202
1203 platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
1204
1205 final FlutterJNI jni = new FlutterJNI();
1206 jni.attachToNative();
1207 attach(jni, platformViewsController);
1208
1209 final FlutterView flutterView = mock(FlutterView.class);
1210 platformViewsController.attachToView(flutterView);
1211
1212 final PlatformOverlayView overlayImageView = mock(PlatformOverlayView.class);
1213 when(overlayImageView.acquireLatestImage()).thenReturn(true);
1214
1215 final FlutterOverlaySurface overlaySurface =
1216 platformViewsController.createOverlaySurface(overlayImageView);
1217
1218 platformViewsController.onDisplayOverlaySurface(
1219 overlaySurface.getId(), /* x=*/ 0, /* y=*/ 0, /* width=*/ 10, /* height=*/ 10);
1220
1221 platformViewsController.detachFromView();
1222
1223 platformViewsController.destroyOverlaySurfaces();
1224 verify(overlayImageView, times(1)).closeImageReader();
1225 verify(overlayImageView, times(1)).detachFromRenderer();
1226 }
1227
1228 @Test
1229 @Config(shadows = {ShadowFlutterSurfaceView.class, ShadowFlutterJNI.class})
1231 final PlatformViewsController platformViewsController = new PlatformViewsController();
1232
1233 final int platformViewId = 0;
1234 assertNull(platformViewsController.getPlatformViewById(platformViewId));
1235
1236 final PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
1237 final PlatformView platformView = mock(PlatformView.class);
1238 when(platformView.getView()).thenReturn(mock(View.class));
1239 when(viewFactory.create(any(), eq(platformViewId), any())).thenReturn(platformView);
1240
1241 platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
1242
1243 final FlutterJNI jni = new FlutterJNI();
1244 jni.attachToNative();
1245 attach(jni, platformViewsController);
1246
1247 final FlutterView flutterView = mock(FlutterView.class);
1248 platformViewsController.attachToView(flutterView);
1249
1250 final PlatformOverlayView overlayImageView = mock(PlatformOverlayView.class);
1251 when(overlayImageView.acquireLatestImage()).thenReturn(true);
1252
1253 final FlutterOverlaySurface overlaySurface =
1254 platformViewsController.createOverlaySurface(overlayImageView);
1255
1256 platformViewsController.onDisplayOverlaySurface(
1257 overlaySurface.getId(), /* x=*/ 0, /* y=*/ 0, /* width=*/ 10, /* height=*/ 10);
1258
1259 platformViewsController.destroyOverlaySurfaces();
1260 verify(flutterView, never()).removeView(overlayImageView);
1261 }
1262
1263 @Test
1265 final PlatformViewsController platformViewsController = new PlatformViewsController();
1266 boolean shouldProxying = platformViewsController.checkInputConnectionProxy(null);
1267 assertFalse(shouldProxying);
1268 }
1269
1270 @Test
1271 @Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
1273 final PlatformViewsController platformViewsController = new PlatformViewsController();
1274
1275 final int platformViewId = 0;
1276 assertNull(platformViewsController.getPlatformViewById(platformViewId));
1277
1278 final PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
1279 final PlatformView platformView = mock(PlatformView.class);
1280 final View androidView = mock(View.class);
1281 when(platformView.getView()).thenReturn(androidView);
1282 when(viewFactory.create(any(), eq(platformViewId), any())).thenReturn(platformView);
1283
1284 platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
1285
1286 final FlutterJNI jni = new FlutterJNI();
1287 jni.attachToNative();
1288 final FlutterView flutterView = attach(jni, platformViewsController);
1289
1290 jni.onFirstFrame();
1291
1292 // Simulate create call from the framework.
1293 createPlatformView(jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ true);
1294
1295 // Produce a frame that displays a platform view and an overlay surface.
1296 platformViewsController.onBeginFrame();
1297 platformViewsController.onDisplayPlatformView(
1298 platformViewId,
1299 /* x=*/ 0,
1300 /* y=*/ 0,
1301 /* width=*/ 10,
1302 /* height=*/ 10,
1303 /* viewWidth=*/ 10,
1304 /* viewHeight=*/ 10,
1305 /* mutatorsStack=*/ new FlutterMutatorsStack());
1306
1307 assertEquals(flutterView.getChildCount(), 3);
1308
1309 final View view = flutterView.getChildAt(1);
1310 assertTrue(view instanceof FlutterImageView);
1311
1312 // Simulate dispose call from the framework.
1313 disposePlatformView(jni, platformViewsController, platformViewId);
1314 }
1315
1316 @Test
1317 @Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
1319 final PlatformViewsController platformViewsController = new PlatformViewsController();
1320
1321 final int platformViewId = 0;
1322 assertNull(platformViewsController.getPlatformViewById(platformViewId));
1323
1324 final PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
1325 final PlatformView platformView = mock(PlatformView.class);
1326 final View androidView = mock(View.class);
1327 when(platformView.getView()).thenReturn(androidView);
1328 when(viewFactory.create(any(), eq(platformViewId), any())).thenReturn(platformView);
1329
1330 platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
1331
1332 final FlutterJNI jni = new FlutterJNI();
1333 jni.attachToNative();
1334 final FlutterView flutterView = attach(jni, platformViewsController);
1335
1336 jni.onFirstFrame();
1337
1338 // Simulate setting render surface conversion flag.
1339 synchronizeToNativeViewHierarchy(jni, platformViewsController, false);
1340
1341 // Simulate create call from the framework.
1342 createPlatformView(jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ true);
1343
1344 // Produce a frame that displays a platform view and an overlay surface.
1345 platformViewsController.onBeginFrame();
1346 platformViewsController.onDisplayPlatformView(
1347 platformViewId,
1348 /* x=*/ 0,
1349 /* y=*/ 0,
1350 /* width=*/ 10,
1351 /* height=*/ 10,
1352 /* viewWidth=*/ 10,
1353 /* viewHeight=*/ 10,
1354 /* mutatorsStack=*/ new FlutterMutatorsStack());
1355
1356 assertEquals(flutterView.getChildCount(), 2);
1357 assertTrue(!(flutterView.getChildAt(0) instanceof PlatformOverlayView));
1358 assertTrue(flutterView.getChildAt(1) instanceof FlutterMutatorView);
1359
1360 // Simulate dispose call from the framework.
1361 disposePlatformView(jni, platformViewsController, platformViewId);
1362 }
1363
1364 @Test
1365 @Config(shadows = {ShadowFlutterJNI.class, ShadowPlatformTaskQueue.class})
1367 PlatformViewsController platformViewsController = new PlatformViewsController();
1368 platformViewsController.setSoftwareRendering(true);
1369
1370 int platformViewId = 100;
1371 assertNull(platformViewsController.getPlatformViewById(platformViewId));
1372
1373 PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
1374 PlatformView platformView = mock(PlatformView.class);
1375 View androidView = mock(View.class);
1376 when(platformView.getView()).thenReturn(androidView);
1377 when(viewFactory.create(any(), eq(platformViewId), any())).thenReturn(platformView);
1378 platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
1379
1380 FlutterJNI jni = new FlutterJNI();
1381 FlutterView initFlutterView = mock(FlutterView.class);
1382 attachToFlutterView(jni, platformViewsController, initFlutterView);
1383
1384 createPlatformView(
1385 jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ false);
1386 verify(initFlutterView, times(1)).addView(any(PlatformViewWrapper.class));
1387
1388 platformViewsController.detachFromView();
1389 verify(initFlutterView, times(1)).removeView(any(PlatformViewWrapper.class));
1390
1391 FlutterView newFlutterView = mock(FlutterView.class);
1392 platformViewsController.attachToView(newFlutterView);
1393 verify(newFlutterView, times(1)).addView(any(PlatformViewWrapper.class));
1394 }
1395
1396 @Config(
1397 shadows = {
1398 ShadowFlutterSurfaceView.class,
1399 ShadowFlutterJNI.class,
1400 ShadowPlatformTaskQueue.class
1401 })
1403 final PlatformViewsController platformViewsController = new PlatformViewsController();
1404
1405 final int platformViewId = 0;
1406 assertNull(platformViewsController.getPlatformViewById(platformViewId));
1407
1408 final PlatformViewFactory viewFactory = mock(PlatformViewFactory.class);
1409 final PlatformView platformView = mock(PlatformView.class);
1410 final View androidView = mock(View.class);
1411 when(platformView.getView()).thenReturn(androidView);
1412 when(viewFactory.create(any(), eq(platformViewId), any())).thenReturn(platformView);
1413
1414 platformViewsController.getRegistry().registerViewFactory("testType", viewFactory);
1415
1416 final FlutterJNI jni = new FlutterJNI();
1417 jni.attachToNative();
1418
1419 final FlutterView flutterView = attach(jni, platformViewsController);
1420
1421 jni.onFirstFrame();
1422
1423 // Simulate create call from the framework.
1424 createPlatformView(jni, platformViewsController, platformViewId, "testType", /* hybrid=*/ true);
1425
1426 // The simulation creates an Overlay on top of the PlatformView
1427 // This is going to be called `flutterView.convertToImageView`
1428 platformViewsController.createOverlaySurface();
1429 platformViewsController.onDisplayOverlaySurface(platformViewId, 0, 0, 10, 10);
1430
1431 // This will contain three views: Background ImageView、PlatformView、Overlay ImageView
1432 assertEquals(flutterView.getChildCount(), 3);
1433
1434 FlutterImageView imageView = flutterView.getCurrentImageSurface();
1435
1436 // Make sure the ImageView is inside the current FlutterView.
1437 assertTrue(imageView != null);
1438 assertTrue(flutterView.indexOfChild(imageView) != -1);
1439
1440 // Make sure the overlayView is inside the current FlutterView
1441 assertTrue(platformViewsController.getOverlayLayerViews().size() != 0);
1442 PlatformOverlayView overlayView = platformViewsController.getOverlayLayerViews().get(0);
1443 assertTrue(overlayView != null);
1444 assertTrue(flutterView.indexOfChild(overlayView) != -1);
1445
1446 // Simulate in a new frame, there's no PlatformView, which is called
1447 // `flutterView.revertImageView`. And register a `FlutterUiDisplayListener` callback.
1448 // During callback execution it will invoke `flutterImageView.detachFromRenderer()`.
1449 platformViewsController.onBeginFrame();
1450 platformViewsController.onEndFrame();
1451
1452 // Invoke all registered `FlutterUiDisplayListener` callback
1453 jni.onFirstFrame();
1454
1455 assertEquals(null, flutterView.getCurrentImageSurface());
1456
1457 // Make sure the background ImageVIew is not in the FlutterView
1458 assertTrue(flutterView.indexOfChild(imageView) == -1);
1459
1460 // Make sure the overlay ImageVIew is not in the FlutterView
1461 assertTrue(flutterView.indexOfChild(overlayView) == -1);
1462 }
1463
1464 private static ByteBuffer encodeMethodCall(MethodCall call) {
1466 buffer.rewind();
1467 return buffer;
1468 }
1469
1470 private static void createPlatformView(
1471 FlutterJNI jni,
1472 PlatformViewsController platformViewsController,
1473 int platformViewId,
1474 String viewType,
1475 boolean hybrid) {
1476 final Map<String, Object> args = new HashMap<>();
1477 args.put("hybrid", hybrid);
1478 args.put("id", platformViewId);
1479 args.put("viewType", viewType);
1480 args.put("direction", 0);
1481 args.put("width", 1.0);
1482 args.put("height", 1.0);
1483
1484 final MethodCall platformCreateMethodCall = new MethodCall("create", args);
1485
1487 "flutter/platform_views",
1488 encodeMethodCall(platformCreateMethodCall),
1489 /*replyId=*/ 0,
1490 /*messageData=*/ 0);
1491 }
1492
1493 private static void setLayoutDirection(
1494 FlutterJNI jni,
1495 PlatformViewsController platformViewsController,
1496 int platformViewId,
1497 int direction) {
1498 final Map<String, Object> args = new HashMap<>();
1499 args.put("id", platformViewId);
1500 args.put("direction", direction);
1501
1502 final MethodCall platformSetDirectionMethodCall = new MethodCall("setDirection", args);
1503
1505 "flutter/platform_views",
1506 encodeMethodCall(platformSetDirectionMethodCall),
1507 /*replyId=*/ 0,
1508 /*messageData=*/ 0);
1509 }
1510
1511 private static void resize(
1512 FlutterJNI jni,
1513 PlatformViewsController platformViewsController,
1514 int platformViewId,
1515 double width,
1516 double height) {
1517 final Map<String, Object> args = new HashMap<>();
1518 args.put("id", platformViewId);
1519 args.put("width", width);
1520 args.put("height", height);
1521
1522 final MethodCall platformResizeMethodCall = new MethodCall("resize", args);
1523
1524 jni.handlePlatformMessage(
1525 "flutter/platform_views",
1526 encodeMethodCall(platformResizeMethodCall),
1527 /*replyId=*/ 0,
1528 /*messageData=*/ 0);
1529 }
1530
1531 private static void disposePlatformView(
1532 FlutterJNI jni, PlatformViewsController platformViewsController, int platformViewId) {
1533
1534 final Map<String, Object> args = new HashMap<>();
1535 args.put("hybrid", true);
1536 args.put("id", platformViewId);
1537
1538 final MethodCall platformDisposeMethodCall = new MethodCall("dispose", args);
1539
1540 jni.handlePlatformMessage(
1541 "flutter/platform_views",
1542 encodeMethodCall(platformDisposeMethodCall),
1543 /*replyId=*/ 0,
1544 /*messageData=*/ 0);
1545 }
1546
1547 private static void synchronizeToNativeViewHierarchy(
1548 FlutterJNI jni, PlatformViewsController platformViewsController, boolean yes) {
1549
1550 final MethodCall convertMethodCall = new MethodCall("synchronizeToNativeViewHierarchy", yes);
1551
1552 jni.handlePlatformMessage(
1553 "flutter/platform_views",
1554 encodeMethodCall(convertMethodCall),
1555 /*replyId=*/ 0,
1556 /*messageData=*/ 0);
1557 }
1558
1559 private static FlutterView attach(
1560 FlutterJNI jni, PlatformViewsController platformViewsController) {
1561 final Context context = ApplicationProvider.getApplicationContext();
1562 final FlutterView flutterView =
1563 new FlutterView(context, new FlutterSurfaceView(context)) {
1564 @Override
1565 public FlutterImageView createImageView() {
1566 final FlutterImageView view = mock(FlutterImageView.class);
1567 when(view.acquireLatestImage()).thenReturn(true);
1568 return mock(FlutterImageView.class);
1569 }
1570 };
1571 attachToFlutterView(jni, platformViewsController, flutterView);
1572 return flutterView;
1573 }
1574
1575 private static void attachToFlutterView(
1576 FlutterJNI jni, PlatformViewsController platformViewsController, FlutterView flutterView) {
1577 final DartExecutor executor = new DartExecutor(jni, mock(AssetManager.class));
1578 executor.onAttachedToJNI();
1579
1580 final Context context = ApplicationProvider.getApplicationContext();
1581 final TextureRegistry registry =
1582 new TextureRegistry() {
1583 public void TextureRegistry() {}
1584
1585 @Override
1586 public SurfaceTextureEntry createSurfaceTexture() {
1587 return registerSurfaceTexture(mock(SurfaceTexture.class));
1588 }
1589
1590 @Override
1591 public SurfaceTextureEntry registerSurfaceTexture(SurfaceTexture surfaceTexture) {
1592 return new SurfaceTextureEntry() {
1593 @NonNull
1594 @Override
1595 public SurfaceTexture surfaceTexture() {
1596 return mock(SurfaceTexture.class);
1597 }
1598
1599 @Override
1600 public long id() {
1601 return 0;
1602 }
1603
1604 @Override
1605 public void release() {}
1606 };
1607 }
1608
1609 @Override
1610 public ImageTextureEntry createImageTexture() {
1611 return new ImageTextureEntry() {
1612 @Override
1613 public long id() {
1614 return 0;
1615 }
1616
1617 @Override
1618 public void release() {}
1619
1620 @Override
1621 public void pushImage(Image image) {}
1622 };
1623 }
1624
1625 @Override
1626 public SurfaceProducer createSurfaceProducer() {
1627 return new SurfaceProducer() {
1628 @Override
1629 public long id() {
1630 return 0;
1631 }
1632
1633 @Override
1634 public void release() {}
1635
1636 @Override
1637 public int getWidth() {
1638 return 0;
1639 }
1640
1641 @Override
1642 public int getHeight() {
1643 return 0;
1644 }
1645
1646 @Override
1647 public void setSize(int width, int height) {}
1648
1649 @Override
1650 public Surface getSurface() {
1651 return null;
1652 }
1653
1654 public void scheduleFrame() {}
1655 };
1656 }
1657 };
1658
1659 platformViewsController.attach(context, registry, executor);
1660
1661 final FlutterEngine engine = mock(FlutterEngine.class);
1662 when(engine.getRenderer()).thenReturn(new FlutterRenderer(jni));
1663 when(engine.getMouseCursorChannel()).thenReturn(mock(MouseCursorChannel.class));
1664 when(engine.getTextInputChannel()).thenReturn(mock(TextInputChannel.class));
1665 when(engine.getSettingsChannel()).thenReturn(new SettingsChannel(executor));
1666 when(engine.getPlatformViewsController()).thenReturn(platformViewsController);
1667 when(engine.getLocalizationPlugin()).thenReturn(mock(LocalizationPlugin.class));
1668 when(engine.getAccessibilityChannel()).thenReturn(mock(AccessibilityChannel.class));
1669 when(engine.getDartExecutor()).thenReturn(executor);
1670
1671 flutterView.attachToFlutterEngine(engine);
1672 platformViewsController.attachToView(flutterView);
1673 }
1674
1675 /**
1676 * For convenience when writing tests, this allows us to make fake messages from Flutter via
1677 * Platform Channels. Typically those calls happen on the ui thread which dispatches to the
1678 * platform thread. Since tests run on the platform thread it makes it difficult to test without
1679 * this, but isn't technically required.
1680 */
1681 @Implements(io.flutter.embedding.engine.dart.PlatformTaskQueue.class)
1682 public static class ShadowPlatformTaskQueue {
1683 @Implementation
1684 public void dispatch(Runnable runnable) {
1685 runnable.run();
1686 }
1687 }
1688
1689 /**
1690 * The shadow class of {@link Presentation} to simulate Presentation showing logic.
1691 *
1692 * <p>Robolectric doesn't support VirtualDisplay creating correctly now, so this shadow class is
1693 * used to simulate custom logic for Presentation.
1694 */
1695 @Implements(Presentation.class)
1696 public static class ShadowPresentation extends ShadowDialog {
1697 private boolean isShowing = false;
1698
1700
1701 @Implementation
1702 protected void show() {
1703 isShowing = true;
1704 }
1705
1706 @Implementation
1707 protected void dismiss() {
1708 isShowing = false;
1709 }
1710
1711 @Implementation
1712 protected boolean isShowing() {
1713 return isShowing;
1714 }
1715 }
1716
1717 @Implements(FlutterJNI.class)
1718 public static class ShadowFlutterJNI {
1719 private static SparseArray<ByteBuffer> replies = new SparseArray<>();
1720
1722
1723 @Implementation
1725 return false;
1726 }
1727
1728 @Implementation
1729 public long performNativeAttach(FlutterJNI flutterJNI) {
1730 return 1;
1731 }
1732
1733 @Implementation
1735 String channel, ByteBuffer message, int position, int responseId) {}
1736
1737 @Implementation
1738 public void onSurfaceCreated(Surface surface) {}
1739
1740 @Implementation
1741 public void onSurfaceDestroyed() {}
1742
1743 @Implementation
1744 public void onSurfaceWindowChanged(Surface surface) {}
1745
1746 @Implementation
1748 float devicePixelRatio,
1749 int physicalWidth,
1750 int physicalHeight,
1751 int physicalPaddingTop,
1752 int physicalPaddingRight,
1753 int physicalPaddingBottom,
1754 int physicalPaddingLeft,
1755 int physicalViewInsetTop,
1756 int physicalViewInsetRight,
1757 int physicalViewInsetBottom,
1758 int physicalViewInsetLeft,
1759 int systemGestureInsetTop,
1760 int systemGestureInsetRight,
1761 int systemGestureInsetBottom,
1762 int systemGestureInsetLeft,
1763 int physicalTouchSlop,
1764 int[] displayFeaturesBounds,
1765 int[] displayFeaturesType,
1766 int[] displayFeaturesState) {}
1767
1768 @Implementation
1770 int responseId, ByteBuffer message, int position) {
1771 replies.put(responseId, message);
1772 }
1773
1774 public static SparseArray<ByteBuffer> getResponses() {
1775 return replies;
1776 }
1777 }
1778
1779 @Implements(SurfaceView.class)
1780 public static class ShadowFlutterSurfaceView extends ShadowSurfaceView {
1781 private final FakeSurfaceHolder holder = new FakeSurfaceHolder();
1782
1783 public static class FakeSurfaceHolder extends ShadowSurfaceView.FakeSurfaceHolder {
1784 private final Surface surface = mock(Surface.class);
1785
1786 public Surface getSurface() {
1787 return surface;
1788 }
1789
1790 @Implementation
1791 public void addCallback(SurfaceHolder.Callback callback) {
1792 callback.surfaceCreated(this);
1793 }
1794 }
1795
1797
1798 @Implementation
1799 public SurfaceHolder getHolder() {
1800 return holder;
1801 }
1802 }
1803}
static SkISize times(const SkISize &size, float factor)
m reset()
static bool eq(const SkM44 &a, const SkM44 &b, float tol)
Definition: M44Test.cpp:18
MotionEventId track(@NonNull MotionEvent event)
void handlePlatformMessage( @NonNull final String channel, ByteBuffer message, final int replyId, final long messageData)
ByteBuffer encodeMethodCall(@NonNull MethodCall methodCall)
abstract PlatformView create(Context context, int viewId, @Nullable Object args)
void invokePlatformMessageResponseCallback(int responseId, ByteBuffer message, int position)
void dispatchPlatformMessage(String channel, ByteBuffer message, int position, int responseId)
void setViewportMetrics(float devicePixelRatio, int physicalWidth, int physicalHeight, int physicalPaddingTop, int physicalPaddingRight, int physicalPaddingBottom, int physicalPaddingLeft, int physicalViewInsetTop, int physicalViewInsetRight, int physicalViewInsetBottom, int physicalViewInsetLeft, int systemGestureInsetTop, int systemGestureInsetRight, int systemGestureInsetBottom, int systemGestureInsetLeft, int physicalTouchSlop, int[] displayFeaturesBounds, int[] displayFeaturesType, int[] displayFeaturesState)
MotionEvent toMotionEvent(float density, PlatformViewsChannel.PlatformViewTouch touch, boolean usingVirtualDiplay)
void onDisplayPlatformView(int viewId, int x, int y, int width, int height, int viewWidth, int viewHeight, @NonNull FlutterMutatorsStack mutatorsStack)
void attachToView(@NonNull FlutterView newFlutterView)
FlutterOverlaySurface createOverlaySurface(@NonNull PlatformOverlayView imageView)
void onDisplayOverlaySurface(int id, int x, int y, int width, int height)
final HashMap< Integer, VirtualDisplayController > vdControllers
void resize(final int width, final int height, final Runnable onNewSizeFrameAvailable)
FlutterEngine engine
Definition: main.cc:68
VkSurfaceKHR surface
Definition: main.cc:49
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
static ::testing::Matcher< GBytes * > MethodCall(const std::string &name, ::testing::Matcher< FlValue * > args)
boolean registerViewFactory(@NonNull String viewTypeId, @NonNull PlatformViewFactory factory)
Win32Message message
sk_sp< const SkImage > image
Definition: SkRecords.h:269
def call(args)
Definition: dom.py:159
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
CanvasImage Image
Definition: dart_ui.cc:55
SIT bool any(const Vec< 1, T > &x)
Definition: SkVx.h:530
int32_t height
int32_t width
const uintptr_t id