5package io.flutter.plugin.platform;
7import static io.flutter.Build.API_LEVELS;
9import android.annotation.TargetApi;
10import android.content.ComponentCallbacks2;
12import android.content.MutableContextWrapper;
16import android.view.MotionEvent.PointerCoords;
17import android.view.MotionEvent.PointerProperties;
21import android.widget.FrameLayout;
22import androidx.annotation.NonNull;
23import androidx.annotation.Nullable;
24import androidx.annotation.UiThread;
25import androidx.annotation.VisibleForTesting;
27import io.flutter.embedding.android.AndroidTouchProcessor;
28import io.flutter.embedding.android.FlutterView;
29import io.flutter.embedding.android.MotionEventTracker;
30import io.flutter.embedding.engine.FlutterOverlaySurface;
31import io.flutter.embedding.engine.dart.DartExecutor;
32import io.flutter.embedding.engine.mutatorsstack.*;
33import io.flutter.embedding.engine.renderer.FlutterRenderer;
34import io.flutter.embedding.engine.systemchannels.PlatformViewsChannel;
35import io.flutter.plugin.editing.TextInputPlugin;
36import io.flutter.util.ViewUtils;
37import io.flutter.view.AccessibilityBridge;
38import io.flutter.view.TextureRegistry;
39import java.util.ArrayList;
40import java.util.HashMap;
41import java.util.HashSet;
52 private static final String TAG =
"PlatformViewsController";
65 private static Class[] VIEW_TYPES_REQUIRE_VIRTUAL_DISPLAY = {SurfaceView.class};
72 private Context context;
92 @VisibleForTesting
final HashMap<Integer, VirtualDisplayController>
vdControllers;
101 private final SparseArray<PlatformView> platformViews;
116 private final SparseArray<FlutterMutatorView> platformViewParent;
119 private final SparseArray<PlatformOverlayView> overlayLayerViews;
127 private final SparseArray<PlatformViewWrapper> viewWrappers;
130 private int nextOverlayLayerId = 0;
133 private boolean flutterViewConvertedToImageView =
false;
138 private boolean synchronizeToNativeViewHierarchy =
true;
141 private final HashSet<Integer> currentFrameUsedOverlayLayerIds;
144 private final HashSet<Integer> currentFrameUsedPlatformViewIds;
150 private boolean usesSoftwareRendering =
false;
152 private static boolean enableImageRenderTarget =
true;
154 private static boolean enableSurfaceProducerRenderTarget =
true;
156 private final PlatformViewsChannel.PlatformViewsHandler channelHandler =
162 public void createForPlatformViewLayer(
165 enforceMinimumAndroidApiVersion(19);
166 ensureValidRequest(request);
170 configureForHybridComposition(platformView, request);
176 public long createForTextureLayer(
178 ensureValidRequest(request);
179 final int viewId = request.viewId;
180 if (viewWrappers.get(viewId) !=
null) {
181 throw new IllegalStateException(
182 "Trying to create an already created platform view, view id: " + viewId);
184 if (textureRegistry ==
null) {
185 throw new IllegalStateException(
186 "Texture registry is null. This means that platform views controller was detached,"
190 if (flutterView ==
null) {
191 throw new IllegalStateException(
192 "Flutter view is null. This means the platform views controller doesn't have an"
193 +
" attached view, view id: "
199 final View embeddedView = platformView.
getView();
200 if (embeddedView.getParent() !=
null) {
201 throw new IllegalStateException(
202 "The Android view returned from PlatformView#getView() was already added to a"
212 final boolean supportsTextureLayerMode =
213 Build.VERSION.SDK_INT >= API_LEVELS.API_23
215 embeddedView, VIEW_TYPES_REQUIRE_VIRTUAL_DISPLAY);
219 if (!supportsTextureLayerMode) {
220 if (request.displayMode
223 configureForHybridComposition(platformView, request);
225 }
else if (!usesSoftwareRendering) {
226 return configureForVirtualDisplay(platformView, request);
236 public void dispose(
int viewId) {
237 final PlatformView platformView = platformViews.get(viewId);
238 if (platformView ==
null) {
239 Log.
e(
TAG,
"Disposing unknown platform view with id: " + viewId);
242 if (platformView.
getView() !=
null) {
243 final View embeddedView = platformView.
getView();
244 final ViewGroup pvParent = (ViewGroup) embeddedView.getParent();
245 if (pvParent !=
null) {
249 pvParent.removeView(embeddedView);
252 platformViews.remove(viewId);
255 }
catch (RuntimeException exception) {
256 Log.
e(
TAG,
"Disposing platform view threw an exception", exception);
260 final View embeddedView = vdController.
getView();
261 if (embeddedView !=
null) {
271 if (viewWrapper !=
null) {
272 viewWrapper.removeAllViews();
276 final ViewGroup wrapperParent = (ViewGroup) viewWrapper.getParent();
277 if (wrapperParent !=
null) {
278 wrapperParent.removeView(viewWrapper);
280 viewWrappers.remove(viewId);
285 if (parentView !=
null) {
286 parentView.removeAllViews();
289 final ViewGroup mutatorViewParent = (ViewGroup) parentView.getParent();
290 if (mutatorViewParent !=
null) {
291 mutatorViewParent.removeView(parentView);
293 platformViewParent.remove(viewId);
298 public void offset(
int viewId,
double top,
double left) {
311 if (viewWrapper ==
null) {
312 Log.
e(
TAG,
"Setting offset for unknown platform view with id: " + viewId);
315 final int physicalTop = toPhysicalPixels(top);
316 final int physicalLeft = toPhysicalPixels(left);
317 final FrameLayout.LayoutParams layoutParams =
318 (FrameLayout.LayoutParams) viewWrapper.getLayoutParams();
319 layoutParams.topMargin = physicalTop;
320 layoutParams.leftMargin = physicalLeft;
328 final int physicalWidth = toPhysicalPixels(request.newLogicalWidth);
329 final int physicalHeight = toPhysicalPixels(request.newLogicalHeight);
330 final int viewId = request.viewId;
333 final float originalDisplayDensity = getDisplayDensity();
339 lockInputConnection(vdController);
344 unlockInputConnection(vdController);
348 final float displayDensity =
349 context ==
null ? originalDisplayDensity : getDisplayDensity();
358 final PlatformView platformView = platformViews.get(viewId);
360 if (platformView ==
null || viewWrapper ==
null) {
361 Log.
e(
TAG,
"Resizing unknown platform view with id: " + viewId);
376 final ViewGroup.LayoutParams viewWrapperLayoutParams = viewWrapper.getLayoutParams();
377 viewWrapperLayoutParams.width = physicalWidth;
378 viewWrapperLayoutParams.height = physicalHeight;
381 final View embeddedView = platformView.
getView();
382 if (embeddedView !=
null) {
383 final ViewGroup.LayoutParams embeddedViewLayoutParams = embeddedView.getLayoutParams();
384 embeddedViewLayoutParams.width = physicalWidth;
385 embeddedViewLayoutParams.height = physicalHeight;
386 embeddedView.setLayoutParams(embeddedViewLayoutParams);
396 final int viewId = touch.viewId;
397 final float density = context.getResources().getDisplayMetrics().density;
401 final MotionEvent
event =
toMotionEvent(density, touch,
true);
406 final PlatformView platformView = platformViews.get(viewId);
407 if (platformView ==
null) {
408 Log.
e(
TAG,
"Sending touch to an unknown view with id: " + viewId);
411 final View view = platformView.
getView();
413 Log.
e(
TAG,
"Sending touch to a null view with id: " + viewId);
416 final MotionEvent
event =
toMotionEvent(density, touch,
false);
417 view.dispatchTouchEvent(
event);
421 public void setDirection(
int viewId,
int direction) {
422 if (!validateDirection(direction)) {
423 throw new IllegalStateException(
424 "Trying to set unknown direction value: "
435 embeddedView = controller.
getView();
437 final PlatformView platformView = platformViews.get(viewId);
438 if (platformView ==
null) {
439 Log.
e(
TAG,
"Setting direction to an unknown view with id: " + viewId);
442 embeddedView = platformView.
getView();
444 if (embeddedView ==
null) {
445 Log.
e(
TAG,
"Setting direction to a null view with id: " + viewId);
448 embeddedView.setLayoutDirection(direction);
452 public void clearFocus(
int viewId) {
457 embeddedView = controller.
getView();
459 final PlatformView platformView = platformViews.get(viewId);
460 if (platformView ==
null) {
461 Log.
e(
TAG,
"Clearing focus on an unknown view with id: " + viewId);
464 embeddedView = platformView.
getView();
466 if (embeddedView ==
null) {
467 Log.
e(
TAG,
"Clearing focus on a null view with id: " + viewId);
470 embeddedView.clearFocus();
474 public void synchronizeToNativeViewHierarchy(
boolean yes) {
475 synchronizeToNativeViewHierarchy = yes;
480 private void enforceMinimumAndroidApiVersion(
int minSdkVersion) {
481 if (
Build.VERSION.SDK_INT < minSdkVersion) {
482 throw new IllegalStateException(
483 "Trying to use platform views with API "
484 +
Build.VERSION.SDK_INT
485 +
", required API level is: "
490 private void ensureValidRequest(
491 @NonNull PlatformViewsChannel.PlatformViewCreationRequest request) {
492 if (!validateDirection(request.direction)) {
493 throw new IllegalStateException(
494 "Trying to create a view with unknown direction value: "
504 @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
508 if (viewFactory ==
null) {
509 throw new IllegalStateException(
510 "Trying to create a platform view of unregistered type: " + request.viewType);
513 Object createParams =
null;
514 if (request.params !=
null) {
521 final Context mutableContext = wrapContext ?
new MutableContextWrapper(context) : context;
523 viewFactory.
create(mutableContext, request.viewId, createParams);
526 final View embeddedView = platformView.
getView();
527 if (embeddedView ==
null) {
528 throw new IllegalStateException(
529 "PlatformView#getView() returned null, but an Android view reference was expected.");
531 embeddedView.setLayoutDirection(request.direction);
532 platformViews.put(request.viewId, platformView);
533 maybeInvokeOnFlutterViewAttached(platformView);
538 private void configureForHybridComposition(
541 enforceMinimumAndroidApiVersion(19);
542 Log.
i(TAG,
"Using hybrid composition for platform view: " + request.viewId);
546 private long configureForVirtualDisplay(
547 @NonNull PlatformView platformView,
548 @NonNull PlatformViewsChannel.PlatformViewCreationRequest request) {
553 enforceMinimumAndroidApiVersion(20);
555 Log.
i(TAG,
"Hosting view in a virtual display for platform view: " + request.viewId);
557 final PlatformViewRenderTarget renderTarget = makePlatformViewRenderTarget(textureRegistry);
558 final int physicalWidth = toPhysicalPixels(request.logicalWidth);
559 final int physicalHeight = toPhysicalPixels(request.logicalHeight);
560 final VirtualDisplayController vdController =
561 VirtualDisplayController.create(
563 accessibilityEventsDelegate,
570 (view, hasFocus) -> {
572 platformViewsChannel.invokeViewFocused(request.viewId);
576 if (vdController ==
null) {
577 throw new IllegalStateException(
578 "Failed creating virtual display for a "
588 final View embeddedView = platformView.getView();
591 return renderTarget.getId();
596 @TargetApi(API_LEVELS.API_23)
597 @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
598 public
long configureForTextureLayerComposition(
606 enforceMinimumAndroidApiVersion(23);
607 Log.
i(
TAG,
"Hosting view in view hierarchy for platform view: " + request.viewId);
609 final int physicalWidth = toPhysicalPixels(request.logicalWidth);
610 final int physicalHeight = toPhysicalPixels(request.logicalHeight);
613 if (usesSoftwareRendering) {
619 textureId = renderTarget.
getId();
624 final FrameLayout.LayoutParams viewWrapperLayoutParams =
625 new FrameLayout.LayoutParams(physicalWidth, physicalHeight);
628 final int physicalTop = toPhysicalPixels(request.logicalTop);
629 final int physicalLeft = toPhysicalPixels(request.logicalLeft);
630 viewWrapperLayoutParams.topMargin = physicalTop;
631 viewWrapperLayoutParams.leftMargin = physicalLeft;
635 final View embeddedView = platformView.getView();
636 embeddedView.setLayoutParams(
new FrameLayout.LayoutParams(physicalWidth, physicalHeight));
645 embeddedView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
648 viewWrapper.addView(embeddedView);
661 flutterView.addView(viewWrapper);
662 viewWrappers.append(request.viewId, viewWrapper);
664 maybeInvokeOnFlutterViewAttached(platformView);
676 private static void translateMotionEvent(
677 MotionEvent originalEvent, PointerCoords[] pointerCoords) {
678 if (pointerCoords.length < 1) {
682 float xOffset = pointerCoords[0].x - originalEvent.getX();
683 float yOffset = pointerCoords[0].y - originalEvent.getY();
685 originalEvent.offsetLocation(xOffset, yOffset);
691 MotionEventTracker.MotionEventId motionEventId =
693 MotionEvent trackedEvent = motionEventTracker.
pop(motionEventId);
700 PointerCoords[] pointerCoords =
701 parsePointerCoordsList(touch.rawPointerCoords, density)
702 .toArray(
new PointerCoords[touch.pointerCount]);
704 if (!usingVirtualDiplay && trackedEvent !=
null) {
707 translateMotionEvent(trackedEvent, pointerCoords);
713 PointerProperties[] pointerProperties =
714 parsePointerPropertiesList(touch.rawPointerPropertiesList)
715 .toArray(
new PointerProperties[touch.pointerCount]);
719 return MotionEvent.obtain(
720 touch.downTime.longValue(),
721 touch.eventTime.longValue(),
738 vdControllers =
new HashMap<>();
740 contextToEmbeddedView =
new HashMap<>();
741 overlayLayerViews =
new SparseArray<>();
742 currentFrameUsedOverlayLayerIds =
new HashSet<>();
743 currentFrameUsedPlatformViewIds =
new HashSet<>();
744 viewWrappers =
new SparseArray<>();
745 platformViews =
new SparseArray<>();
746 platformViewParent =
new SparseArray<>();
761 @Nullable Context context,
764 if (this.context !=
null) {
765 throw new AssertionError(
766 "A PlatformViewsController can only be attached to a single output target.\n"
767 +
"attach was called while the PlatformViewsController was already attached.");
769 this.context = context;
770 this.textureRegistry = textureRegistry;
788 usesSoftwareRendering = useSoftwareRendering;
801 if (platformViewsChannel !=
null) {
804 destroyOverlaySurfaces();
805 platformViewsChannel =
null;
807 textureRegistry =
null;
817 flutterView = newFlutterView;
819 for (
int index = 0; index < viewWrappers.size(); index++) {
821 flutterView.addView(view);
824 for (
int index = 0; index < platformViewParent.size(); index++) {
826 flutterView.addView(view);
829 for (
int index = 0; index < platformViews.size(); index++) {
844 for (
int index = 0; index < viewWrappers.size(); index++) {
846 flutterView.removeView(view);
849 for (
int index = 0; index < platformViewParent.size(); index++) {
851 flutterView.removeView(view);
854 destroyOverlaySurfaces();
855 removeOverlaySurfaces();
857 flutterViewConvertedToImageView =
false;
860 for (
int index = 0; index < platformViews.size(); index++) {
866 private void maybeInvokeOnFlutterViewAttached(
PlatformView view) {
867 if (flutterView ==
null) {
868 Log.
i(
TAG,
"null flutterView");
916 if (!contextToEmbeddedView.containsKey(view.getContext())) {
919 View platformView = contextToEmbeddedView.get(view.getContext());
920 if (platformView == view) {
923 return platformView.checkInputConnectionProxy(view);
953 if (usesVirtualDisplay(viewId)) {
958 final PlatformView platformView = platformViews.get(viewId);
959 if (platformView ==
null) {
967 return vdControllers.containsKey(
id);
975 controller.onInputConnectionLocked();
978 private void unlockInputConnection(@NonNull VirtualDisplayController controller) {
983 controller.onInputConnectionUnlocked();
986 private static PlatformViewRenderTarget makePlatformViewRenderTarget(
987 TextureRegistry textureRegistry) {
988 if (enableSurfaceProducerRenderTarget &&
Build.VERSION.SDK_INT >= API_LEVELS.API_29) {
989 final TextureRegistry.SurfaceProducer textureEntry = textureRegistry.createSurfaceProducer();
990 Log.i(
TAG,
"PlatformView is using SurfaceProducer backend");
991 return new SurfaceProducerPlatformViewRenderTarget(textureEntry);
993 if (enableImageRenderTarget &&
Build.VERSION.SDK_INT >= API_LEVELS.API_29) {
994 final TextureRegistry.ImageTextureEntry textureEntry = textureRegistry.createImageTexture();
995 Log.i(
TAG,
"PlatformView is using ImageReader backend");
996 return new ImageReaderPlatformViewRenderTarget(textureEntry);
998 final TextureRegistry.SurfaceTextureEntry textureEntry = textureRegistry.createSurfaceTexture();
999 Log.i(
TAG,
"PlatformView is using SurfaceTexture backend");
1000 return new SurfaceTexturePlatformViewRenderTarget(textureEntry);
1003 private static boolean validateDirection(
int direction) {
1004 return direction == View.LAYOUT_DIRECTION_LTR || direction == View.LAYOUT_DIRECTION_RTL;
1007 @SuppressWarnings(
"unchecked")
1008 private static
List<PointerProperties> parsePointerPropertiesList(Object rawPropertiesList) {
1011 for (Object o : rawProperties) {
1012 pointerProperties.
add(parsePointerProperties(o));
1014 return pointerProperties;
1017 @SuppressWarnings(
"unchecked")
1018 private static PointerProperties parsePointerProperties(Object rawProperties) {
1020 PointerProperties properties =
new MotionEvent.PointerProperties();
1021 properties.id = (
int) propertiesList.get(0);
1022 properties.toolType = (
int) propertiesList.get(1);
1026 @SuppressWarnings(
"unchecked")
1027 private static
List<PointerCoords> parsePointerCoordsList(Object rawCoordsList,
float density) {
1030 for (Object o : rawCoords) {
1031 pointerCoords.
add(parsePointerCoords(o, density));
1033 return pointerCoords;
1036 @SuppressWarnings(
"unchecked")
1037 private static PointerCoords parsePointerCoords(Object rawCoords,
float density) {
1039 PointerCoords coords =
new MotionEvent.PointerCoords();
1040 coords.orientation = (
float) (
double) coordsList.get(0);
1041 coords.pressure = (
float) (
double) coordsList.get(1);
1042 coords.size = (
float) (
double) coordsList.get(2);
1043 coords.toolMajor = (
float) ((
double) coordsList.get(3) * density);
1044 coords.toolMinor = (
float) ((
double) coordsList.get(4) * density);
1045 coords.touchMajor = (
float) ((
double) coordsList.get(5) * density);
1046 coords.touchMinor = (
float) ((
double) coordsList.get(6) * density);
1047 coords.x = (
float) ((
double) coordsList.get(7) * density);
1048 coords.y = (
float) ((
double) coordsList.get(8) * density);
1052 private float getDisplayDensity() {
1053 return context.getResources().getDisplayMetrics().density;
1056 private int toPhysicalPixels(
double logicalPixels) {
1057 return (
int) Math.round(logicalPixels * getDisplayDensity());
1060 private int toLogicalPixels(
double physicalPixels,
float displayDensity) {
1061 return (
int) Math.round(physicalPixels / displayDensity);
1064 private int toLogicalPixels(
double physicalPixels) {
1065 return toLogicalPixels(physicalPixels, getDisplayDensity());
1068 private void diposeAllViews() {
1069 while (platformViews.size() > 0) {
1070 final int viewId = platformViews.keyAt(0);
1072 channelHandler.dispose(viewId);
1078 if (
level < ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
1101 channelHandler.dispose(viewId);
1104 private void initializeRootImageViewIfNeeded() {
1105 if (synchronizeToNativeViewHierarchy && !flutterViewConvertedToImageView) {
1107 flutterViewConvertedToImageView =
true;
1119 final PlatformView platformView = platformViews.get(viewId);
1120 if (platformView ==
null) {
1121 throw new IllegalStateException(
1122 "Platform view hasn't been initialized from the platform view channel.");
1124 if (platformViewParent.get(viewId) !=
null) {
1127 final View embeddedView = platformView.
getView();
1128 if (embeddedView ==
null) {
1129 throw new IllegalStateException(
1130 "PlatformView#getView() returned null, but an Android view reference was expected.");
1132 if (embeddedView.getParent() !=
null) {
1133 throw new IllegalStateException(
1134 "The Android view returned from PlatformView#getView() was already added to a parent"
1139 context, context.getResources().getDisplayMetrics().density, androidTouchProcessor);
1142 (view, hasFocus) -> {
1150 platformViewParent.put(viewId, parentView);
1159 embeddedView.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
1161 parentView.addView(embeddedView);
1162 flutterView.addView(parentView);
1191 initializeRootImageViewIfNeeded();
1192 initializePlatformViewIfNeeded(viewId);
1196 parentView.setVisibility(View.VISIBLE);
1197 parentView.bringToFront();
1199 final FrameLayout.LayoutParams layoutParams =
1200 new FrameLayout.LayoutParams(viewWidth, viewHeight);
1201 final View view = platformViews.get(viewId).
getView();
1203 view.setLayoutParams(layoutParams);
1204 view.bringToFront();
1206 currentFrameUsedPlatformViewIds.add(viewId);
1220 if (overlayLayerViews.get(
id) ==
null) {
1221 throw new IllegalStateException(
"The overlay surface (id:" +
id +
") doesn't exist");
1223 initializeRootImageViewIfNeeded();
1226 if (overlayView.getParent() ==
null) {
1227 flutterView.addView(overlayView);
1230 FrameLayout.LayoutParams layoutParams =
new FrameLayout.LayoutParams((
int)
width, (
int)
height);
1231 layoutParams.leftMargin = (
int)
x;
1232 layoutParams.topMargin = (
int)
y;
1233 overlayView.setLayoutParams(layoutParams);
1234 overlayView.setVisibility(View.VISIBLE);
1235 overlayView.bringToFront();
1236 currentFrameUsedOverlayLayerIds.add(
id);
1240 currentFrameUsedOverlayLayerIds.clear();
1241 currentFrameUsedPlatformViewIds.clear();
1254 if (flutterViewConvertedToImageView && currentFrameUsedPlatformViewIds.isEmpty()) {
1255 flutterViewConvertedToImageView =
false;
1272 final boolean isFrameRenderedUsingImageReaders =
1274 finishFrame(isFrameRenderedUsingImageReaders);
1277 private void finishFrame(
boolean isFrameRenderedUsingImageReaders) {
1278 for (
int i = 0;
i < overlayLayerViews.size();
i++) {
1279 final int overlayId = overlayLayerViews.keyAt(
i);
1282 if (currentFrameUsedOverlayLayerIds.contains(overlayId)) {
1285 isFrameRenderedUsingImageReaders &= didAcquireOverlaySurfaceImage;
1290 if (!flutterViewConvertedToImageView) {
1294 overlayView.setVisibility(View.GONE);
1295 flutterView.removeView(overlayView);
1299 for (
int i = 0;
i < platformViewParent.size();
i++) {
1300 final int viewId = platformViewParent.keyAt(
i);
1301 final View parentView = platformViewParent.get(viewId);
1312 if (currentFrameUsedPlatformViewIds.contains(viewId)
1313 && (isFrameRenderedUsingImageReaders || !synchronizeToNativeViewHierarchy)) {
1314 parentView.setVisibility(View.VISIBLE);
1316 parentView.setVisibility(View.GONE);
1331 final int id = nextOverlayLayerId++;
1332 overlayLayerViews.put(
id, imageView);
1351 return createOverlaySurface(
1353 flutterView.getContext(),
1354 flutterView.getWidth(),
1355 flutterView.getHeight(),
1356 accessibilityEventsDelegate));
1365 for (
int viewId = 0; viewId < overlayLayerViews.size(); viewId++) {
1376 private void removeOverlaySurfaces() {
1377 if (flutterView ==
null) {
1378 Log.
e(
TAG,
"removeOverlaySurfaces called while flutter view is null");
1381 for (
int viewId = 0; viewId < overlayLayerViews.size(); viewId++) {
1382 flutterView.removeView(overlayLayerViews.valueAt(viewId));
1384 overlayLayerViews.clear();
1389 return overlayLayerViews;
void add(sk_sp< SkIDChangeListener > listener) SK_EXCLUDES(fMutex)
static void e(@NonNull String tag, @NonNull String message)
static void i(@NonNull String tag, @NonNull String message)
void detachFromRenderer()
boolean acquireLatestImage()
boolean acquireLatestImageViewFrame()
void attachOverlaySurfaceToRender(@NonNull FlutterImageView view)
void convertToImageView()
void revertImageView(@NonNull Runnable onDone)
static MotionEventId from(long id)
static MotionEventTracker getInstance()
MotionEvent pop(@NonNull MotionEventId eventId)
static boolean hasChildViewOfType(@Nullable View root, Class<? extends View >[] viewTypes)
T decodeMessage(@Nullable ByteBuffer message)
FlutterTextInputPlugin * textInputPlugin
void Log(const char *format,...) SK_PRINTF_LIKE(1
def Build(configs, env, options)