5package io.flutter.embedding.android;
7import static io.flutter.Build.API_LEVELS;
9import android.annotation.SuppressLint;
10import android.annotation.TargetApi;
13import android.content.res.Configuration;
14import android.database.ContentObserver;
20import android.provider.Settings;
21import android.text.format.DateFormat;
22import android.util.AttributeSet;
24import android.view.DisplayCutout;
30import android.view.ViewConfiguration;
32import android.view.ViewStructure;
33import android.view.WindowInsets;
34import android.view.WindowManager;
35import android.view.accessibility.AccessibilityManager;
36import android.view.accessibility.AccessibilityNodeProvider;
37import android.view.autofill.AutofillValue;
38import android.view.inputmethod.EditorInfo;
39import android.view.inputmethod.InputConnection;
40import android.view.textservice.SpellCheckerInfo;
41import android.view.textservice.TextServicesManager;
42import android.widget.FrameLayout;
43import androidx.annotation.NonNull;
44import androidx.annotation.Nullable;
45import androidx.annotation.RequiresApi;
46import androidx.annotation.VisibleForTesting;
47import androidx.core.content.ContextCompat;
48import androidx.core.util.Consumer;
49import androidx.window.java.layout.WindowInfoTrackerCallbackAdapter;
50import androidx.window.layout.DisplayFeature;
51import androidx.window.layout.FoldingFeature;
52import androidx.window.layout.FoldingFeature.OcclusionType;
53import androidx.window.layout.FoldingFeature.State;
54import androidx.window.layout.WindowInfoTracker;
55import androidx.window.layout.WindowLayoutInfo;
57import io.flutter.embedding.engine.FlutterEngine;
58import io.flutter.embedding.engine.renderer.FlutterRenderer;
59import io.flutter.embedding.engine.renderer.FlutterRenderer.DisplayFeatureState;
60import io.flutter.embedding.engine.renderer.FlutterRenderer.DisplayFeatureType;
61import io.flutter.embedding.engine.renderer.FlutterUiDisplayListener;
62import io.flutter.embedding.engine.renderer.RenderSurface;
63import io.flutter.embedding.engine.systemchannels.SettingsChannel;
64import io.flutter.plugin.common.BinaryMessenger;
65import io.flutter.plugin.editing.SpellCheckPlugin;
66import io.flutter.plugin.editing.TextInputPlugin;
67import io.flutter.plugin.localization.LocalizationPlugin;
68import io.flutter.plugin.mouse.MouseCursorPlugin;
69import io.flutter.plugin.platform.PlatformViewsController;
70import io.flutter.util.ViewUtils;
71import io.flutter.view.AccessibilityBridge;
72import java.lang.reflect.InvocationTargetException;
73import java.lang.reflect.Method;
74import java.util.ArrayList;
75import java.util.HashSet;
109 private static final String TAG =
"FlutterView";
117 private final Set<FlutterUiDisplayListener> flutterUiDisplayListeners =
new HashSet<>();
118 private boolean isFlutterUiDisplayed;
124 private final Set<FlutterEngineAttachmentListener> flutterEngineAttachmentListeners =
139 @Nullable
private TextServicesManager textServicesManager;
144 private final FlutterRenderer.ViewportMetrics viewportMetrics =
147 private final AccessibilityBridge.OnAccessibilityChangeListener 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);
317 @NonNull Context context,
320 super(context,
null);
330 throw new IllegalArgumentException(
331 "RenderMode not supported with this constructor: " + renderMode);
338 @NonNull Context context,
341 super(context, attrs);
343 this.flutterSurfaceView = flutterSurfaceView;
344 this.renderSurface = flutterSurfaceView;
350 @NonNull Context context,
352 @NonNull FlutterTextureView flutterTextureView) {
353 super(context, attrs);
355 this.flutterTextureView = flutterTextureView;
356 this.renderSurface = flutterTextureView;
362 @NonNull Context context,
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();
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();
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();
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) {
554 final FoldingFeature feature = (FoldingFeature) displayFeature;
555 if (feature.getOcclusionType() == OcclusionType.FULL) {
560 if (feature.getState() ==
State.FLAT) {
562 }
else if (feature.getState() ==
State.HALF_OPENED) {
571 displayFeature.getBounds(),
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);
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;
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")
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();
1104 mouseCursorPlugin =
new MouseCursorPlugin(
this, this.flutterEngine.getMouseCursorChannel());
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 =
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;
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) {
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(
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
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();
GrGeometryProcessor::AttributeSet AttributeSet
static void v(@NonNull String tag, @NonNull String message)
static void e(@NonNull String tag, @NonNull String message)
View findViewByAccessibilityIdTraversal(int accessibilityId)
boolean checkInputConnectionProxy(View view)
FlutterView(@NonNull Context context, @NonNull RenderMode renderMode)
InputConnection onCreateInputConnection(@NonNull EditorInfo outAttrs)
FlutterView(@NonNull Context context)
boolean onTextInputKeyEvent(@NonNull KeyEvent keyEvent)
void removeOnFirstFrameRenderedListener(@NonNull FlutterUiDisplayListener listener)
FlutterView(@NonNull Context context, @NonNull TransparencyMode transparencyMode)
void detachFromFlutterEngine()
void onConfigurationChanged(@NonNull Configuration newConfig)
FlutterView(@NonNull Context context, @NonNull FlutterSurfaceView flutterSurfaceView)
FlutterImageView createImageView()
FlutterView(@NonNull Context context, @NonNull FlutterImageView flutterImageView)
boolean onTouchEvent(@NonNull MotionEvent event)
boolean hasRenderedFirstFrame()
final WindowInsets onApplyWindowInsets(@NonNull WindowInsets insets)
FlutterView( @NonNull Context context, @NonNull RenderMode renderMode, @NonNull TransparencyMode transparencyMode)
boolean acquireLatestImageViewFrame()
void addOnFirstFrameRenderedListener(@NonNull FlutterUiDisplayListener listener)
boolean onHoverEvent(@NonNull MotionEvent event)
FlutterImageView getCurrentImageSurface()
BinaryMessenger getBinaryMessenger()
boolean dispatchKeyEvent(@NonNull KeyEvent event)
void attachOverlaySurfaceToRender(@NonNull FlutterImageView view)
void attachToFlutterEngine(@NonNull FlutterEngine flutterEngine)
RenderSurface renderSurface
boolean onGenericMotionEvent(@NonNull MotionEvent event)
void setWindowInfoListenerDisplayFeatures(WindowLayoutInfo layoutInfo)
void redispatch(@NonNull KeyEvent keyEvent)
void convertToImageView()
PointerIcon getSystemPointerIcon(int type)
WindowInfoRepositoryCallbackAdapterWrapper createWindowInfoRepo()
void onDetachedFromWindow()
void onAttachedToWindow()
FlutterView(@NonNull Context context, @Nullable AttributeSet attrs)
void revertImageView(@NonNull Runnable onDone)
void onSizeChanged(int width, int height, int oldWidth, int oldHeight)
AccessibilityNodeProvider getAccessibilityNodeProvider()
FlutterView(@NonNull Context context, @NonNull FlutterTextureView flutterTextureView)
void removeIsDisplayingFlutterUiListener(@NonNull FlutterUiDisplayListener listener)
void stopRenderingToSurface()
void addIsDisplayingFlutterUiListener(@NonNull FlutterUiDisplayListener listener)
void setSemanticsEnabled(boolean enabled)
static Activity getActivity(@Nullable Context context)
static void calculateMaximumDisplayMetrics( @Nullable Context context, @NonNull DisplayUpdater updater)
FlutterSemanticsFlag flags
void detachFromRenderer()
void attachToRenderer(@NonNull FlutterRenderer renderer)
FlutterRenderer getAttachedRenderer()
FlutterTextInputPlugin * textInputPlugin
Optional< SkRect > bounds
void Log(const char *format,...) SK_PRINTF_LIKE(1
def Build(configs, env, options)