5package io.flutter.view;
7import static io.flutter.Build.API_LEVELS;
9import android.annotation.SuppressLint;
10import android.annotation.TargetApi;
13import android.content.res.Configuration;
16import android.graphics.PixelFormat;
17import android.graphics.SurfaceTexture;
20import android.text.format.DateFormat;
21import android.util.AttributeSet;
23import android.view.DisplayCutout;
28import android.view.SurfaceHolder;
31import 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.inputmethod.InputMethodManager;
42import androidx.annotation.NonNull;
43import androidx.annotation.RequiresApi;
44import androidx.annotation.UiThread;
46import io.flutter.app.FlutterPluginRegistry;
47import io.flutter.embedding.android.AndroidTouchProcessor;
48import io.flutter.embedding.android.KeyboardManager;
49import io.flutter.embedding.engine.dart.DartExecutor;
50import io.flutter.embedding.engine.renderer.FlutterRenderer;
51import io.flutter.embedding.engine.renderer.SurfaceTextureWrapper;
52import io.flutter.embedding.engine.systemchannels.AccessibilityChannel;
53import io.flutter.embedding.engine.systemchannels.BackGestureChannel;
54import io.flutter.embedding.engine.systemchannels.LifecycleChannel;
55import io.flutter.embedding.engine.systemchannels.LocalizationChannel;
56import io.flutter.embedding.engine.systemchannels.MouseCursorChannel;
57import io.flutter.embedding.engine.systemchannels.NavigationChannel;
58import io.flutter.embedding.engine.systemchannels.PlatformChannel;
59import io.flutter.embedding.engine.systemchannels.SettingsChannel;
60import io.flutter.embedding.engine.systemchannels.SystemChannel;
61import io.flutter.embedding.engine.systemchannels.TextInputChannel;
62import io.flutter.plugin.common.ActivityLifecycleListener;
63import io.flutter.plugin.common.BinaryMessenger;
64import io.flutter.plugin.editing.TextInputPlugin;
65import io.flutter.plugin.localization.LocalizationPlugin;
66import io.flutter.plugin.mouse.MouseCursorPlugin;
67import io.flutter.plugin.platform.PlatformPlugin;
68import io.flutter.plugin.platform.PlatformViewsController;
69import io.flutter.util.ViewUtils;
70import java.nio.ByteBuffer;
71import java.util.ArrayList;
73import java.util.concurrent.atomic.AtomicLong;
105 private static final String TAG =
"FlutterView";
135 private final InputMethodManager mImm;
142 private final SurfaceHolder.Callback mSurfaceCallback;
146 private final AtomicLong nextTextureId =
new AtomicLong(0
L);
148 private boolean mIsSoftwareRenderingEnabled =
false;
149 private boolean didRenderFirstFrame =
false;
151 private final AccessibilityBridge.OnAccessibilityChangeListener onAccessibilityChangeListener =
154 public void onAccessibilityChanged(
155 boolean isAccessibilityEnabled,
boolean isTouchExplorationEnabled) {
156 resetWillNotDraw(isAccessibilityEnabled, isTouchExplorationEnabled);
165 this(context, attrs,
null);
169 super(context, attrs);
172 if (activity ==
null) {
173 throw new IllegalArgumentException(
"Bad context");
176 if (nativeView ==
null) {
179 mNativeView = nativeView;
186 mMetrics.devicePixelRatio = context.getResources().getDisplayMetrics().density;
187 mMetrics.physicalTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
189 setFocusableInTouchMode(
true);
194 new SurfaceHolder.Callback() {
196 public void surfaceCreated(SurfaceHolder holder) {
202 public void surfaceChanged(SurfaceHolder holder,
int format,
int width,
int height) {
208 public void surfaceDestroyed(SurfaceHolder holder) {
213 getHolder().addCallback(mSurfaceCallback);
215 mActivityLifecycleListeners =
new ArrayList<>();
216 mFirstFrameListeners =
new ArrayList<>();
236 mImm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
246 mMouseCursorPlugin =
null;
249 androidTouchProcessor =
260 sendUserPlatformSettingsToDart();
271 if (
event.getAction() == KeyEvent.ACTION_DOWN &&
event.getRepeatCount() == 0) {
273 getKeyDispatcherState().startTracking(
event,
this);
274 }
else if (
event.getAction() == KeyEvent.ACTION_UP) {
276 getKeyDispatcherState().handleUpEvent(
event);
302 mActivityLifecycleListeners.add(listener);
315 listener.onPostResume();
334 return didRenderFirstFrame;
342 mFirstFrameListeners.add(listener);
347 mFirstFrameListeners.remove(listener);
360 setZOrderOnTop(
false);
400 private void sendUserPlatformSettingsToDart() {
402 boolean isNightModeOn =
403 (getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK)
404 == Configuration.UI_MODE_NIGHT_YES;
413 .setUse24HourFormat(DateFormat.is24HourFormat(getContext()))
414 .setPlatformBrightness(brightness)
420 super.onConfigurationChanged(newConfig);
422 sendUserPlatformSettingsToDart();
430 if (!isAttached())
return null;
431 getHolder().removeCallback(mSurfaceCallback);
440 if (!isAttached())
return;
442 getHolder().removeCallback(mSurfaceCallback);
443 releaseAccessibilityNodeProvider();
464 super.onProvideAutofillVirtualStructure(structure,
flags);
476 return super.onTouchEvent(
event);
479 requestUnbufferedDispatch(
event);
487 return super.onHoverEvent(
event);
490 boolean handled = mAccessibilityNodeProvider.onAccessibilityHoverEvent(
event);
509 return handled ?
true : super.onGenericMotionEvent(
event);
514 mMetrics.physicalWidth =
width;
515 mMetrics.physicalHeight =
height;
516 updateViewportMetrics();
517 super.onSizeChanged(
width,
height, oldWidth, oldHeight);
525 private enum ZeroSides {
532 private ZeroSides calculateShouldZeroSides() {
537 Context context = getContext();
538 int orientation = context.getResources().getConfiguration().orientation;
540 ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE))
544 if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
545 if (rotation == Surface.ROTATION_90) {
546 return ZeroSides.RIGHT;
547 }
else if (rotation == Surface.ROTATION_270) {
549 return Build.VERSION.SDK_INT >= API_LEVELS.API_23 ? ZeroSides.LEFT : ZeroSides.RIGHT;
552 else if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) {
553 return ZeroSides.BOTH;
558 return ZeroSides.NONE;
570 private int guessBottomKeyboardInset(WindowInsets insets) {
571 int screenHeight = getRootView().getHeight();
574 final double keyboardHeightRatioHeuristic = 0.18;
575 if (insets.getSystemWindowInsetBottom() < screenHeight * keyboardHeightRatioHeuristic) {
580 return insets.getSystemWindowInsetBottom();
590 @SuppressLint({
"InlinedApi",
"NewApi"})
594 Insets systemGestureInsets = insets.getSystemGestureInsets();
595 mMetrics.systemGestureInsetTop = systemGestureInsets.top;
596 mMetrics.systemGestureInsetRight = systemGestureInsets.right;
597 mMetrics.systemGestureInsetBottom = systemGestureInsets.bottom;
598 mMetrics.systemGestureInsetLeft = systemGestureInsets.left;
601 boolean statusBarVisible = (SYSTEM_UI_FLAG_FULLSCREEN & getWindowSystemUiVisibility()) == 0;
602 boolean navigationBarVisible =
603 (SYSTEM_UI_FLAG_HIDE_NAVIGATION & getWindowSystemUiVisibility()) == 0;
607 if (navigationBarVisible) {
608 mask = mask |
android.view.WindowInsets.Type.navigationBars();
610 if (statusBarVisible) {
611 mask = mask |
android.view.WindowInsets.Type.statusBars();
613 Insets uiInsets = insets.getInsets(mask);
614 mMetrics.physicalViewPaddingTop = uiInsets.top;
615 mMetrics.physicalViewPaddingRight = uiInsets.right;
616 mMetrics.physicalViewPaddingBottom = uiInsets.bottom;
617 mMetrics.physicalViewPaddingLeft = uiInsets.left;
619 Insets imeInsets = insets.getInsets(
android.view.WindowInsets.Type.ime());
620 mMetrics.physicalViewInsetTop = imeInsets.top;
621 mMetrics.physicalViewInsetRight = imeInsets.right;
622 mMetrics.physicalViewInsetBottom = imeInsets.bottom;
623 mMetrics.physicalViewInsetLeft = imeInsets.left;
625 Insets systemGestureInsets =
626 insets.getInsets(
android.view.WindowInsets.Type.systemGestures());
627 mMetrics.systemGestureInsetTop = systemGestureInsets.top;
628 mMetrics.systemGestureInsetRight = systemGestureInsets.right;
629 mMetrics.systemGestureInsetBottom = systemGestureInsets.bottom;
630 mMetrics.systemGestureInsetLeft = systemGestureInsets.left;
635 DisplayCutout cutout = insets.getDisplayCutout();
636 if (cutout !=
null) {
637 Insets waterfallInsets = cutout.getWaterfallInsets();
638 mMetrics.physicalViewPaddingTop =
641 cutout.getSafeInsetTop());
642 mMetrics.physicalViewPaddingRight =
645 cutout.getSafeInsetRight());
646 mMetrics.physicalViewPaddingBottom =
649 cutout.getSafeInsetBottom());
650 mMetrics.physicalViewPaddingLeft =
653 cutout.getSafeInsetLeft());
658 ZeroSides zeroSides = ZeroSides.NONE;
659 if (!navigationBarVisible) {
660 zeroSides = calculateShouldZeroSides();
665 mMetrics.physicalViewPaddingTop = statusBarVisible ? insets.getSystemWindowInsetTop() : 0;
666 mMetrics.physicalViewPaddingRight =
667 zeroSides == ZeroSides.RIGHT || zeroSides == ZeroSides.BOTH
669 : insets.getSystemWindowInsetRight();
670 mMetrics.physicalViewPaddingBottom =
671 navigationBarVisible && guessBottomKeyboardInset(insets) == 0
672 ? insets.getSystemWindowInsetBottom()
674 mMetrics.physicalViewPaddingLeft =
675 zeroSides == ZeroSides.LEFT || zeroSides == ZeroSides.BOTH
677 : insets.getSystemWindowInsetLeft();
680 mMetrics.physicalViewInsetTop = 0;
681 mMetrics.physicalViewInsetRight = 0;
682 mMetrics.physicalViewInsetBottom = guessBottomKeyboardInset(insets);
683 mMetrics.physicalViewInsetLeft = 0;
686 updateViewportMetrics();
687 return super.onApplyWindowInsets(insets);
690 private boolean isAttached() {
691 return mNativeView !=
null && mNativeView.
isAttached();
695 if (!isAttached())
throw new AssertionError(
"Platform view is not attached");
698 private void preRun() {
703 if (mAccessibilityNodeProvider !=
null) {
704 mAccessibilityNodeProvider.reset();
708 private void postRun() {}
727 private void updateViewportMetrics() {
728 if (!isAttached())
return;
755 didRenderFirstFrame =
true;
760 listener.onFirstFrame();
766 super.onAttachedToWindow();
770 mAccessibilityNodeProvider =
774 (AccessibilityManager) getContext().getSystemService(Context.ACCESSIBILITY_SERVICE),
775 getContext().getContentResolver(),
776 platformViewsController);
777 mAccessibilityNodeProvider.setOnAccessibilityChangeListener(onAccessibilityChangeListener);
780 mAccessibilityNodeProvider.isAccessibilityEnabled(),
781 mAccessibilityNodeProvider.isTouchExplorationEnabled());
786 super.onDetachedFromWindow();
787 releaseAccessibilityNodeProvider();
792 private void resetWillNotDraw(
boolean isAccessibilityEnabled,
boolean isTouchExplorationEnabled) {
793 if (!mIsSoftwareRenderingEnabled) {
794 setWillNotDraw(!(isAccessibilityEnabled || isTouchExplorationEnabled));
796 setWillNotDraw(
false);
802 if (mAccessibilityNodeProvider !=
null && mAccessibilityNodeProvider.isAccessibilityEnabled()) {
803 return mAccessibilityNodeProvider;
812 private void releaseAccessibilityNodeProvider() {
813 if (mAccessibilityNodeProvider !=
null) {
814 mAccessibilityNodeProvider.release();
815 mAccessibilityNodeProvider =
null;
822 @TargetApi(API_LEVELS.API_24)
823 @RequiresApi(API_LEVELS.API_24)
826 return PointerIcon.getSystemIcon(getContext(),
type);
845 getRootView().dispatchKeyEvent(keyEvent);
866 Log.
d(
TAG,
"FlutterView.send called on a detached view, channel=" + channel);
881 @NonNull String channel,
895 final SurfaceTexture surfaceTexture =
new SurfaceTexture(0);
902 throw new UnsupportedOperationException(
"Image textures are not supported in this mode.");
907 throw new UnsupportedOperationException(
908 "SurfaceProducer textures are not supported in this mode.");
914 @NonNull SurfaceTexture surfaceTexture) {
915 surfaceTexture.detachFromGLContext();
923 private final long id;
925 private boolean released;
936 this.
surfaceTexture().setOnFrameAvailableListener(onFrameListener,
new Handler());
939 private SurfaceTexture.OnFrameAvailableListener onFrameListener =
940 new SurfaceTexture.OnFrameAvailableListener() {
942 public void onFrameAvailable(SurfaceTexture
texture) {
943 if (released || mNativeView ==
null) {
958 return textureWrapper;
964 return textureWrapper.surfaceTexture();
static void d(@NonNull String tag, @NonNull String message)
static void e(@NonNull String tag, @NonNull String message)
PlatformViewsController getPlatformViewsController()
boolean onTouchEvent(@NonNull MotionEvent event)
boolean onGenericMotionEvent(@NonNull MotionEvent event, @NonNull Context context)
boolean handleEvent(@NonNull KeyEvent keyEvent)
void onSurfaceDestroyed()
boolean getIsSoftwareRenderingEnabled()
void notifyLowMemoryWarning()
void registerTexture(long textureId, @NonNull SurfaceTextureWrapper textureWrapper)
void onSurfaceCreated(@NonNull Surface surface)
void setLocalizationPlugin(@Nullable LocalizationPlugin localizationPlugin)
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)
void unregisterTexture(long textureId)
void onSurfaceChanged(int width, int height)
void markTextureFrameAvailable(long textureId)
void updateBackGestureProgress(@NonNull BackEvent backEvent)
void startBackGesture(@NonNull BackEvent backEvent)
void pushRoute(@NonNull String route)
void setInitialRoute(@NonNull String initialRoute)
MessageBuilder setTextScaleFactor(float textScaleFactor)
MessageBuilder startMessage()
void sendMemoryPressureWarning()
boolean handleKeyEvent(@NonNull KeyEvent keyEvent)
InputConnection createInputConnection( @NonNull View view, @NonNull KeyboardManager keyboardManager, @NonNull EditorInfo outAttrs)
void onProvideAutofillVirtualStructure(@NonNull ViewStructure structure, int flags)
void autofill(@NonNull SparseArray< AutofillValue > values)
void sendLocalesToFlutter(@NonNull Configuration config)
static Activity getActivity(@Nullable Context context)
static String getLookupKeyForAsset(@NonNull String asset)
void setMessageHandler(String channel, BinaryMessageHandler handler)
FlutterJNI getFlutterJNI()
void send(String channel, ByteBuffer message)
void detachFromFlutterView()
FlutterPluginRegistry getPluginRegistry()
void attachViewAndActivity(FlutterView flutterView, Activity activity)
DartExecutor getDartExecutor()
void runFromBundle(FlutterRunArguments args)
SurfaceTextureRegistryEntry(long id, SurfaceTexture surfaceTexture)
SurfaceTexture surfaceTexture()
SurfaceTextureWrapper textureWrapper()
int physicalViewInsetBottom
int physicalViewPaddingBottom
int physicalViewPaddingLeft
int systemGestureInsetTop
int systemGestureInsetRight
int physicalViewPaddingRight
int physicalViewInsetLeft
int systemGestureInsetBottom
int physicalViewInsetRight
int systemGestureInsetLeft
int physicalViewPaddingTop
void addFirstFrameListener(FirstFrameListener listener)
boolean onHoverEvent(MotionEvent event)
void setInitialRoute(String route)
void onSizeChanged(int width, int height, int oldWidth, int oldHeight)
void removeFirstFrameListener(FirstFrameListener listener)
PointerIcon getSystemPointerIcon(int type)
FlutterNativeView getFlutterNativeView()
String getLookupKeyForAsset(String asset)
void setMessageHandler( @NonNull String channel, @NonNull BinaryMessageHandler handler, @NonNull TaskQueue taskQueue)
void resetAccessibilityTree()
float getDevicePixelRatio()
void onConfigurationChanged(Configuration newConfig)
void redispatch(@NonNull KeyEvent keyEvent)
final WindowInsets onApplyWindowInsets(WindowInsets insets)
void disableBufferingIncomingMessages()
void updateBackGestureProgress(@NonNull BackEvent backEvent)
void setMessageHandler(@NonNull String channel, @NonNull BinaryMessageHandler handler)
FlutterView(Context context, AttributeSet attrs)
void pushRoute(String route)
ImageTextureEntry createImageTexture()
FlutterView(Context context)
boolean dispatchKeyEvent(KeyEvent event)
boolean checkInputConnectionProxy(View view)
void send(String channel, ByteBuffer message)
FlutterNativeView detach()
DartExecutor getDartExecutor()
String getLookupKeyForAsset(String asset, String packageName)
boolean onGenericMotionEvent(MotionEvent event)
BinaryMessenger getBinaryMessenger()
void runFromBundle(FlutterRunArguments args)
TaskQueue makeBackgroundTaskQueue(TaskQueueOptions options)
void onDetachedFromWindow()
TextureRegistry.SurfaceTextureEntry registerSurfaceTexture( @NonNull SurfaceTexture surfaceTexture)
void enableBufferingIncomingMessages()
void disableTransparentBackground()
InputConnection onCreateInputConnection(EditorInfo outAttrs)
SurfaceProducer createSurfaceProducer()
void addActivityLifecycleListener(ActivityLifecycleListener listener)
void send(String channel, ByteBuffer message, BinaryReply callback)
void onProvideAutofillVirtualStructure(ViewStructure structure, int flags)
void startBackGesture(@NonNull BackEvent backEvent)
TextureRegistry.SurfaceTextureEntry createSurfaceTexture()
boolean hasRenderedFirstFrame()
boolean onTextInputKeyEvent(@NonNull KeyEvent keyEvent)
AccessibilityNodeProvider getAccessibilityNodeProvider()
FlutterView(Context context, AttributeSet attrs, FlutterNativeView nativeView)
void onAttachedToWindow()
boolean onTouchEvent(MotionEvent event)
FlutterPluginRegistry getPluginRegistry()
void autofill(SparseArray< AutofillValue > values)
FlutterSemanticsFlag flags
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
uint32_t uint32_t * format
FlutterView getFlutterView()
def Build(configs, env, options)
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 Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however route
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...