108 implements MouseCursorPlugin.MouseCursorViewDelegate,
KeyboardManager.ViewDelegate {
109 private static final String TAG =
"FlutterView";
116 @Nullable
private RenderSurface previousRenderSurface;
117 private final Set<FlutterUiDisplayListener> flutterUiDisplayListeners =
new HashSet<>();
118 private boolean isFlutterUiDisplayed;
124 private final Set<FlutterEngineAttachmentListener> flutterEngineAttachmentListeners =
132 @Nullable
private MouseCursorPlugin mouseCursorPlugin;
133 @Nullable
private TextInputPlugin textInputPlugin;
134 @Nullable
private SpellCheckPlugin spellCheckPlugin;
135 @Nullable
private LocalizationPlugin localizationPlugin;
138 @Nullable
private AccessibilityBridge accessibilityBridge;
139 @Nullable
private TextServicesManager textServicesManager;
144 private final FlutterRenderer.ViewportMetrics viewportMetrics =
147 private final AccessibilityBridge.OnAccessibilityChangeListener onAccessibilityChangeListener =
148 new AccessibilityBridge.OnAccessibilityChangeListener() {
150 public void onAccessibilityChanged(
151 boolean isAccessibilityEnabled,
boolean isTouchExplorationEnabled) {
152 resetWillNotDraw(isAccessibilityEnabled, isTouchExplorationEnabled);
156 private final ContentObserver systemSettingsObserver =
157 new ContentObserver(
new Handler(Looper.getMainLooper())) {
159 public void onChange(
boolean selfChange) {
160 super.onChange(selfChange);
161 if (flutterEngine ==
null) {
164 Log.
v(TAG,
"System settings changed. Sending user settings to Flutter.");
165 sendUserSettingsToFlutter();
169 public boolean deliverSelfNotifications() {
175 private final FlutterUiDisplayListener flutterUiDisplayListener =
176 new FlutterUiDisplayListener() {
178 public void onFlutterUiDisplayed() {
179 isFlutterUiDisplayed =
true;
181 for (FlutterUiDisplayListener listener : flutterUiDisplayListeners) {
182 listener.onFlutterUiDisplayed();
187 public void onFlutterUiNoLongerDisplayed() {
188 isFlutterUiDisplayed =
false;
190 for (FlutterUiDisplayListener listener : flutterUiDisplayListeners) {
191 listener.onFlutterUiNoLongerDisplayed();
196 private final Consumer<WindowLayoutInfo> windowInfoListener =
197 new Consumer<WindowLayoutInfo>() {
199 public void accept(WindowLayoutInfo layoutInfo) {
228 super(context,
null);
237 throw new IllegalArgumentException(
238 "RenderMode not supported with this constructor: " + renderMode);
273 this(context,
null, flutterSurfaceView);
285 this(context,
null, flutterTextureView);
296 this(context,
null, flutterImageView);
320 super(context,
null);
330 throw new IllegalArgumentException(
331 "RenderMode not supported with this constructor: " + renderMode);
341 super(context, attrs);
343 this.flutterSurfaceView = flutterSurfaceView;
344 this.renderSurface = flutterSurfaceView;
352 @NonNull FlutterTextureView flutterTextureView) {
353 super(context, attrs);
355 this.flutterTextureView = flutterTextureView;
356 this.renderSurface = flutterTextureView;
364 @NonNull FlutterImageView flutterImageView) {
365 super(context, attrs);
367 this.flutterImageView = flutterImageView;
368 this.renderSurface = flutterImageView;
373 private void init() {
374 Log.v(TAG,
"Initializing FlutterView");
376 if (flutterSurfaceView !=
null) {
377 Log.v(TAG,
"Internally using a FlutterSurfaceView.");
378 addView(flutterSurfaceView);
379 }
else if (flutterTextureView !=
null) {
380 Log.v(TAG,
"Internally using a FlutterTextureView.");
381 addView(flutterTextureView);
383 Log.v(TAG,
"Internally using a FlutterImageView.");
384 addView(flutterImageView);
389 setFocusableInTouchMode(
true);
390 if (
Build.VERSION.SDK_INT >= API_LEVELS.API_26) {
391 setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_YES);
413 return isFlutterUiDisplayed;
421 flutterUiDisplayListeners.add(listener);
429 flutterUiDisplayListeners.remove(listener);
442 super.onConfigurationChanged(newConfig);
450 if (flutterEngine !=
null) {
451 Log.
v(
TAG,
"Configuration changed. Sending locales and user settings to Flutter.");
452 localizationPlugin.sendLocalesToFlutter(newConfig);
453 sendUserSettingsToFlutter();
455 ViewUtils.calculateMaximumDisplayMetrics(getContext(), flutterEngine);
470 super.onSizeChanged(
width,
height, oldWidth, oldHeight);
473 "Size changed. Sending Flutter new viewport metrics. FlutterView was "
481 viewportMetrics.width =
width;
482 viewportMetrics.height =
height;
483 sendViewportMetricsToFlutter();
490 new WindowInfoTrackerCallbackAdapter(
491 WindowInfoTracker.Companion.getOrCreate(getContext())));
492 }
catch (NoClassDefFoundError noClassDefFoundError) {
510 super.onAttachedToWindow();
512 Activity activity = ViewUtils.getActivity(getContext());
513 if (windowInfoRepo !=
null && activity !=
null) {
514 windowInfoRepo.addWindowLayoutInfoListener(
515 activity, ContextCompat.getMainExecutor(getContext()), windowInfoListener);
526 if (windowInfoRepo !=
null) {
527 windowInfoRepo.removeWindowLayoutInfoListener(windowInfoListener);
529 this.windowInfoRepo =
null;
530 super.onDetachedFromWindow();
537 @TargetApi(API_LEVELS.API_28)
544 for (DisplayFeature displayFeature : displayFeatures) {
547 "WindowInfoTracker Display Feature reported with bounds = "
548 + displayFeature.getBounds().toString()
550 + displayFeature.getClass().getSimpleName());
551 if (displayFeature instanceof FoldingFeature) {
552 DisplayFeatureType
type;
553 DisplayFeatureState
state;
554 final FoldingFeature feature = (FoldingFeature) displayFeature;
555 if (feature.getOcclusionType() == OcclusionType.FULL) {
556 type = DisplayFeatureType.HINGE;
558 type = DisplayFeatureType.FOLD;
560 if (feature.getState() ==
State.FLAT) {
561 state = DisplayFeatureState.POSTURE_FLAT;
562 }
else if (feature.getState() ==
State.HALF_OPENED) {
563 state = DisplayFeatureState.POSTURE_HALF_OPENED;
565 state = DisplayFeatureState.UNKNOWN;
571 displayFeature.getBounds(),
572 DisplayFeatureType.UNKNOWN,
573 DisplayFeatureState.UNKNOWN));
579 if (
Build.VERSION.SDK_INT >= API_LEVELS.API_28) {
580 WindowInsets insets = getRootWindowInsets();
581 if (insets !=
null) {
582 DisplayCutout cutout = insets.getDisplayCutout();
583 if (cutout !=
null) {
584 for (Rect bounds : cutout.getBoundingRects()) {
585 Log.
v(
TAG,
"DisplayCutout area reported with bounds = " + bounds.toString());
591 viewportMetrics.displayFeatures =
result;
592 sendViewportMetricsToFlutter();
600 private enum ZeroSides {
607 private ZeroSides calculateShouldZeroSides() {
612 Context context = getContext();
613 int orientation = context.getResources().getConfiguration().orientation;
615 ((WindowManager) context.getSystemService(
Context.WINDOW_SERVICE))
619 if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
620 if (rotation ==
Surface.ROTATION_90) {
621 return ZeroSides.RIGHT;
622 }
else if (rotation ==
Surface.ROTATION_270) {
624 return Build.VERSION.SDK_INT >= API_LEVELS.API_23 ? ZeroSides.LEFT : ZeroSides.RIGHT;
627 else if (rotation ==
Surface.ROTATION_0 || rotation ==
Surface.ROTATION_180) {
628 return ZeroSides.BOTH;
633 return ZeroSides.NONE;
647 private int guessBottomKeyboardInset(WindowInsets insets) {
648 int screenHeight = getRootView().getHeight();
651 final double keyboardHeightRatioHeuristic = 0.18;
652 if (insets.getSystemWindowInsetBottom() < screenHeight * keyboardHeightRatioHeuristic) {
657 return insets.getSystemWindowInsetBottom();
676 @SuppressLint({
"InlinedApi",
"NewApi"})
679 WindowInsets newInsets = super.onApplyWindowInsets(insets);
682 if (
Build.VERSION.SDK_INT == API_LEVELS.API_29) {
683 Insets systemGestureInsets = insets.getSystemGestureInsets();
684 viewportMetrics.systemGestureInsetTop = systemGestureInsets.top;
685 viewportMetrics.systemGestureInsetRight = systemGestureInsets.right;
686 viewportMetrics.systemGestureInsetBottom = systemGestureInsets.bottom;
687 viewportMetrics.systemGestureInsetLeft = systemGestureInsets.left;
690 boolean statusBarVisible = (SYSTEM_UI_FLAG_FULLSCREEN & getWindowSystemUiVisibility()) == 0;
691 boolean navigationBarVisible =
692 (SYSTEM_UI_FLAG_HIDE_NAVIGATION & getWindowSystemUiVisibility()) == 0;
694 if (
Build.VERSION.SDK_INT >= API_LEVELS.API_30) {
696 if (navigationBarVisible) {
697 mask = mask |
android.view.WindowInsets.Type.navigationBars();
699 if (statusBarVisible) {
700 mask = mask |
android.view.WindowInsets.Type.statusBars();
702 Insets uiInsets = insets.getInsets(mask);
703 viewportMetrics.viewPaddingTop = uiInsets.top;
704 viewportMetrics.viewPaddingRight = uiInsets.right;
705 viewportMetrics.viewPaddingBottom = uiInsets.bottom;
706 viewportMetrics.viewPaddingLeft = uiInsets.left;
708 Insets imeInsets = insets.getInsets(
android.view.WindowInsets.Type.ime());
709 viewportMetrics.viewInsetTop = imeInsets.top;
710 viewportMetrics.viewInsetRight = imeInsets.right;
711 viewportMetrics.viewInsetBottom = imeInsets.bottom;
712 viewportMetrics.viewInsetLeft = imeInsets.left;
714 Insets systemGestureInsets =
715 insets.getInsets(
android.view.WindowInsets.Type.systemGestures());
716 viewportMetrics.systemGestureInsetTop = systemGestureInsets.top;
717 viewportMetrics.systemGestureInsetRight = systemGestureInsets.right;
718 viewportMetrics.systemGestureInsetBottom = systemGestureInsets.bottom;
719 viewportMetrics.systemGestureInsetLeft = systemGestureInsets.left;
724 DisplayCutout cutout = insets.getDisplayCutout();
725 if (cutout !=
null) {
726 Insets waterfallInsets = cutout.getWaterfallInsets();
727 viewportMetrics.viewPaddingTop =
729 Math.max(viewportMetrics.viewPaddingTop, waterfallInsets.top),
730 cutout.getSafeInsetTop());
731 viewportMetrics.viewPaddingRight =
733 Math.max(viewportMetrics.viewPaddingRight, waterfallInsets.right),
734 cutout.getSafeInsetRight());
735 viewportMetrics.viewPaddingBottom =
737 Math.max(viewportMetrics.viewPaddingBottom, waterfallInsets.bottom),
738 cutout.getSafeInsetBottom());
739 viewportMetrics.viewPaddingLeft =
741 Math.max(viewportMetrics.viewPaddingLeft, waterfallInsets.left),
742 cutout.getSafeInsetLeft());
747 ZeroSides zeroSides = ZeroSides.NONE;
748 if (!navigationBarVisible) {
749 zeroSides = calculateShouldZeroSides();
754 viewportMetrics.viewPaddingTop = statusBarVisible ? insets.getSystemWindowInsetTop() : 0;
755 viewportMetrics.viewPaddingRight =
756 zeroSides == ZeroSides.RIGHT || zeroSides == ZeroSides.BOTH
758 : insets.getSystemWindowInsetRight();
759 viewportMetrics.viewPaddingBottom =
760 navigationBarVisible && guessBottomKeyboardInset(insets) == 0
761 ? insets.getSystemWindowInsetBottom()
763 viewportMetrics.viewPaddingLeft =
764 zeroSides == ZeroSides.LEFT || zeroSides == ZeroSides.BOTH
766 : insets.getSystemWindowInsetLeft();
769 viewportMetrics.viewInsetTop = 0;
770 viewportMetrics.viewInsetRight = 0;
771 viewportMetrics.viewInsetBottom = guessBottomKeyboardInset(insets);
772 viewportMetrics.viewInsetLeft = 0;
777 "Updating window insets (onApplyWindowInsets()):\n"
778 +
"Status bar insets: Top: "
779 + viewportMetrics.viewPaddingTop
781 + viewportMetrics.viewPaddingLeft
783 + viewportMetrics.viewPaddingRight
785 +
"Keyboard insets: Bottom: "
786 + viewportMetrics.viewInsetBottom
788 + viewportMetrics.viewInsetLeft
790 + viewportMetrics.viewInsetRight
791 +
"System Gesture Insets - Left: "
792 + viewportMetrics.systemGestureInsetLeft
794 + viewportMetrics.systemGestureInsetTop
796 + viewportMetrics.systemGestureInsetRight
798 + viewportMetrics.viewInsetBottom);
800 sendViewportMetricsToFlutter();
822 if (!isAttachedToFlutterEngine()) {
823 return super.onCreateInputConnection(outAttrs);
826 return textInputPlugin.createInputConnection(
this, keyboardManager, outAttrs);
839 return flutterEngine !=
null
840 ? flutterEngine.getPlatformViewsController().checkInputConnectionProxy(view)
841 : super.checkInputConnectionProxy(view);
857 if (
event.getAction() == KeyEvent.ACTION_DOWN &&
event.getRepeatCount() == 0) {
859 getKeyDispatcherState().startTracking(
event,
this);
860 }
else if (
event.getAction() == KeyEvent.ACTION_UP) {
862 getKeyDispatcherState().handleUpEvent(
event);
868 return (isAttachedToFlutterEngine() && keyboardManager.handleEvent(
event))
869 || super.dispatchKeyEvent(
event);
880 if (!isAttachedToFlutterEngine()) {
881 return super.onTouchEvent(
event);
884 requestUnbufferedDispatch(
event);
886 return androidTouchProcessor.onTouchEvent(
event);
899 isAttachedToFlutterEngine()
900 && androidTouchProcessor.onGenericMotionEvent(
event, getContext());
901 return handled ?
true : super.onGenericMotionEvent(
event);
917 if (!isAttachedToFlutterEngine()) {
918 return super.onHoverEvent(
event);
921 boolean handled = accessibilityBridge.onAccessibilityHoverEvent(
event);
934 if (accessibilityBridge !=
null && accessibilityBridge.isAccessibilityEnabled()) {
935 return accessibilityBridge;
958 @SuppressLint(
"SoonBlockedPrivateApi")
961 if (
Build.VERSION.SDK_INT < API_LEVELS.API_29) {
962 return findViewByAccessibilityIdRootedAtCurrentView(accessibilityId,
this);
969 Method findViewByAccessibilityIdTraversalMethod;
971 findViewByAccessibilityIdTraversalMethod =
972 View.class.getDeclaredMethod(
"findViewByAccessibilityIdTraversal",
int.
class);
973 }
catch (NoSuchMethodException exception) {
976 findViewByAccessibilityIdTraversalMethod.setAccessible(
true);
978 return (View) findViewByAccessibilityIdTraversalMethod.invoke(
this, accessibilityId);
979 }
catch (IllegalAccessException exception) {
981 }
catch (InvocationTargetException exception) {
993 @SuppressLint(
"DiscouragedPrivateApi")
994 private View findViewByAccessibilityIdRootedAtCurrentView(
int accessibilityId, View currentView) {
995 Method getAccessibilityViewIdMethod;
997 getAccessibilityViewIdMethod = View.class.getDeclaredMethod(
"getAccessibilityViewId");
998 }
catch (NoSuchMethodException exception) {
1001 getAccessibilityViewIdMethod.setAccessible(
true);
1003 if (getAccessibilityViewIdMethod.invoke(currentView).equals(accessibilityId)) {
1006 }
catch (IllegalAccessException exception) {
1008 }
catch (InvocationTargetException exception) {
1011 if (currentView instanceof ViewGroup) {
1012 for (
int i = 0; i < ((ViewGroup) currentView).getChildCount(); i++) {
1014 findViewByAccessibilityIdRootedAtCurrentView(
1015 accessibilityId, ((ViewGroup) currentView).getChildAt(i));
1026 private void resetWillNotDraw(
boolean isAccessibilityEnabled,
boolean isTouchExplorationEnabled) {
1027 if (!flutterEngine.getRenderer().isSoftwareRenderingEnabled()) {
1028 setWillNotDraw(!(isAccessibilityEnabled || isTouchExplorationEnabled));
1030 setWillNotDraw(
false);
1037 @TargetApi(API_LEVELS.API_24)
1038 @RequiresApi(API_LEVELS.API_24)
1041 return PointerIcon.getSystemIcon(getContext(),
type);
1049 return flutterEngine.getDartExecutor();
1059 getRootView().dispatchKeyEvent(keyEvent);
1077 Log.
v(
TAG,
"Attaching to a FlutterEngine: " + flutterEngine);
1078 if (isAttachedToFlutterEngine()) {
1079 if (flutterEngine == this.flutterEngine) {
1081 Log.
v(
TAG,
"Already attached to this engine. Doing nothing.");
1088 "Currently attached to a different engine. Detaching and then attaching"
1089 +
" to new engine.");
1093 this.flutterEngine = flutterEngine;
1097 isFlutterUiDisplayed = flutterRenderer.isDisplayingFlutterUi();
1099 flutterRenderer.addIsDisplayingFlutterUiListener(flutterUiDisplayListener);
1103 if (
Build.VERSION.SDK_INT >= API_LEVELS.API_24) {
1104 mouseCursorPlugin =
new MouseCursorPlugin(
this, this.flutterEngine.getMouseCursorChannel());
1107 new TextInputPlugin(
1109 this.flutterEngine.getTextInputChannel(),
1110 this.flutterEngine.getPlatformViewsController());
1113 textServicesManager =
1114 (TextServicesManager)
1115 getContext().getSystemService(
Context.TEXT_SERVICES_MANAGER_SERVICE);
1117 new SpellCheckPlugin(textServicesManager, this.flutterEngine.getSpellCheckChannel());
1118 }
catch (Exception e) {
1119 Log.
e(
TAG,
"TextServicesManager not supported by device, spell check disabled.");
1122 localizationPlugin = this.flutterEngine.getLocalizationPlugin();
1125 androidTouchProcessor =
1127 accessibilityBridge =
1128 new AccessibilityBridge(
1130 flutterEngine.getAccessibilityChannel(),
1131 (AccessibilityManager) getContext().getSystemService(
Context.ACCESSIBILITY_SERVICE),
1132 getContext().getContentResolver(),
1133 this.flutterEngine.getPlatformViewsController());
1134 accessibilityBridge.setOnAccessibilityChangeListener(onAccessibilityChangeListener);
1136 accessibilityBridge.isAccessibilityEnabled(),
1137 accessibilityBridge.isTouchExplorationEnabled());
1141 this.flutterEngine.getPlatformViewsController().attachAccessibilityBridge(accessibilityBridge);
1143 .getPlatformViewsController()
1144 .attachToFlutterRenderer(this.flutterEngine.getRenderer());
1152 sendUserSettingsToFlutter();
1154 .getContentResolver()
1155 .registerContentObserver(
1156 Settings.System.getUriFor(Settings.System.TEXT_SHOW_PASSWORD),
1158 systemSettingsObserver);
1160 sendViewportMetricsToFlutter();
1162 flutterEngine.getPlatformViewsController().attachToView(
this);
1165 for (FlutterEngineAttachmentListener listener : flutterEngineAttachmentListeners) {
1166 listener.onFlutterEngineAttachedToFlutterView(flutterEngine);
1172 if (isFlutterUiDisplayed) {
1173 flutterUiDisplayListener.onFlutterUiDisplayed();
1189 Log.
v(
TAG,
"Detaching from a FlutterEngine: " + flutterEngine);
1190 if (!isAttachedToFlutterEngine()) {
1191 Log.
v(
TAG,
"FlutterView not attached to an engine. Not detaching.");
1196 for (FlutterEngineAttachmentListener listener : flutterEngineAttachmentListeners) {
1197 listener.onFlutterEngineDetachedFromFlutterView();
1200 getContext().getContentResolver().unregisterContentObserver(systemSettingsObserver);
1202 flutterEngine.getPlatformViewsController().detachFromView();
1205 flutterEngine.getPlatformViewsController().detachAccessibilityBridge();
1208 accessibilityBridge.release();
1209 accessibilityBridge =
null;
1217 keyboardManager.destroy();
1218 if (spellCheckPlugin !=
null) {
1219 spellCheckPlugin.destroy();
1222 if (mouseCursorPlugin !=
null) {
1223 mouseCursorPlugin.destroy();
1228 isFlutterUiDisplayed =
false;
1229 flutterRenderer.removeIsDisplayingFlutterUiListener(flutterUiDisplayListener);
1230 flutterRenderer.stopRenderingToSurface();
1231 flutterRenderer.setSemanticsEnabled(
false);
1234 if (previousRenderSurface !=
null &&
renderSurface == flutterImageView) {
1241 previousRenderSurface =
null;
1242 flutterEngine =
null;
1245 private void releaseImageView() {
1246 if (flutterImageView !=
null) {
1247 flutterImageView.closeImageReader();
1251 removeView(flutterImageView);
1252 flutterImageView =
null;
1265 return flutterImageView;
1275 if (flutterImageView ==
null) {
1277 addView(flutterImageView);
1279 flutterImageView.resizeIfNeeded(getWidth(), getHeight());
1284 if (flutterEngine !=
null) {
1285 renderSurface.attachToRenderer(flutterEngine.getRenderer());
1297 if (flutterImageView ==
null) {
1298 Log.
v(
TAG,
"Tried to revert the image view, but no image view is used.");
1301 if (previousRenderSurface ==
null) {
1302 Log.
v(
TAG,
"Tried to revert the image view, but no previous surface was used.");
1306 previousRenderSurface =
null;
1310 if (flutterEngine ==
null || renderer ==
null) {
1311 flutterImageView.detachFromRenderer();
1322 renderer.addIsDisplayingFlutterUiListener(
1323 new FlutterUiDisplayListener() {
1325 public void onFlutterUiDisplayed() {
1326 renderer.removeIsDisplayingFlutterUiListener(
this);
1329 flutterImageView.detachFromRenderer();
1335 public void onFlutterUiNoLongerDisplayed() {
1342 if (flutterEngine !=
null) {
1343 view.attachToRenderer(flutterEngine.getRenderer());
1348 if (flutterImageView !=
null) {
1349 return flutterImageView.acquireLatestImage();
1359 public boolean isAttachedToFlutterEngine() {
1360 return flutterEngine !=
null
1361 && flutterEngine.getRenderer() ==
renderSurface.getAttachedRenderer();
1372 return flutterEngine;
1380 public void addFlutterEngineAttachmentListener(
1381 @NonNull FlutterEngineAttachmentListener listener) {
1382 flutterEngineAttachmentListeners.add(listener);
1390 public void removeFlutterEngineAttachmentListener(
1391 @NonNull FlutterEngineAttachmentListener listener) {
1392 flutterEngineAttachmentListeners.remove(listener);
1404 void sendUserSettingsToFlutter() {
1406 boolean isNightModeOn =
1407 (getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK)
1408 == Configuration.UI_MODE_NIGHT_YES;
1409 SettingsChannel.PlatformBrightness brightness =
1411 ? SettingsChannel.PlatformBrightness.dark
1412 : SettingsChannel.PlatformBrightness.light;
1414 boolean isNativeSpellCheckServiceDefined =
false;
1416 if (textServicesManager !=
null) {
1417 if (Build.VERSION.SDK_INT >= API_LEVELS.API_31) {
1419 textServicesManager.getEnabledSpellCheckerInfos();
1420 boolean gboardSpellCheckerEnabled =
1421 enabledSpellCheckerInfos.stream()
1426 .
equals(
"com.google.android.inputmethod.latin"));
1430 isNativeSpellCheckServiceDefined =
1431 textServicesManager.isSpellCheckerEnabled() && gboardSpellCheckerEnabled;
1433 isNativeSpellCheckServiceDefined =
true;
1438 .getSettingsChannel()
1440 .setTextScaleFactor(getResources().getConfiguration().fontScale)
1441 .setDisplayMetrics(getResources().getDisplayMetrics())
1442 .setNativeSpellCheckServiceDefined(isNativeSpellCheckServiceDefined)
1443 .setBrieflyShowPassword(
1444 Settings.System.getInt(
1445 getContext().getContentResolver(), Settings.System.TEXT_SHOW_PASSWORD, 1)
1447 .setUse24HourFormat(DateFormat.is24HourFormat(getContext()))
1448 .setPlatformBrightness(brightness)
1452 private void sendViewportMetricsToFlutter() {
1453 if (!isAttachedToFlutterEngine()) {
1456 "Tried to send viewport metrics from Android to Flutter but this "
1457 +
"FlutterView was not attached to a FlutterEngine.");
1461 viewportMetrics.devicePixelRatio = getResources().getDisplayMetrics().density;
1462 viewportMetrics.physicalTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
1463 flutterEngine.getRenderer().setViewportMetrics(viewportMetrics);
1467 public void onProvideAutofillVirtualStructure(@NonNull ViewStructure structure,
int flags) {
1468 super.onProvideAutofillVirtualStructure(structure,
flags);
1473 public void autofill(@NonNull SparseArray<AutofillValue> values) {
1478 public void setVisibility(
int visibility) {
1479 super.setVisibility(visibility);
1484 ((FlutterSurfaceView)
renderSurface).setVisibility(visibility);
1493 public interface FlutterEngineAttachmentListener {
1501 void onFlutterEngineDetachedFromFlutterView();