소스 검색

Fix insets on android 15 (#18844)

* fix insets on android 15

* add api diff

* fix nit
Emmanuel Hansen 4 달 전
부모
커밋
2dc808f3e8

+ 12 - 0
api/Avalonia.nupkg.xml

@@ -109,6 +109,18 @@
     <Left>baseline/netstandard2.0/Avalonia.Controls.dll</Left>
     <Right>target/netstandard2.0/Avalonia.Controls.dll</Right>
   </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0006</DiagnosticId>
+    <Target>P:Avalonia.Controls.Platform.IInsetsManager.DisplayEdgeToEdgePreference</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Controls.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Controls.dll</Right>
+  </Suppression>
+  <Suppression>
+    <DiagnosticId>CP0006</DiagnosticId>
+    <Target>P:Avalonia.Controls.Platform.IInsetsManager.DisplaysEdgeToEdge</Target>
+    <Left>baseline/netstandard2.0/Avalonia.Controls.dll</Left>
+    <Right>target/netstandard2.0/Avalonia.Controls.dll</Right>
+  </Suppression>
   <Suppression>
     <DiagnosticId>CP0009</DiagnosticId>
     <Target>T:Avalonia.Diagnostics.StyleDiagnostics</Target>

+ 3 - 3
samples/ControlCatalog/MainView.xaml.cs

@@ -108,14 +108,14 @@ namespace ControlCatalog
                     ViewModel.SafeAreaPadding = insets.SafeAreaPadding;
                 };
 
-                ViewModel.DisplayEdgeToEdge = insets.DisplayEdgeToEdge;
+                ViewModel.DisplayEdgeToEdge = insets.DisplayEdgeToEdgePreference;
                 ViewModel.IsSystemBarVisible = insets.IsSystemBarVisible ?? true;
 
                 ViewModel.PropertyChanged += async (sender, args) =>
                 {
                     if (args.PropertyName == nameof(ViewModel.DisplayEdgeToEdge))
                     {
-                        insets.DisplayEdgeToEdge = ViewModel.DisplayEdgeToEdge;
+                        insets.DisplayEdgeToEdgePreference = ViewModel.DisplayEdgeToEdge;
                     }
                     else if (args.PropertyName == nameof(ViewModel.IsSystemBarVisible))
                     {
@@ -124,7 +124,7 @@ namespace ControlCatalog
 
                     // Give the OS some time to apply new values and refresh the view model.
                     await Task.Delay(100);
-                    ViewModel.DisplayEdgeToEdge = insets.DisplayEdgeToEdge;
+                    ViewModel.DisplayEdgeToEdge = insets.DisplayEdgeToEdgePreference;
                     ViewModel.IsSystemBarVisible = insets.IsSystemBarVisible ?? true;
                 };
             }

+ 2 - 2
samples/SafeAreaDemo/ViewModels/MainViewModel.cs

@@ -72,7 +72,7 @@ namespace SafeAreaDemo.ViewModels
 
                 if (_insetsManager != null)
                 {
-                    _insetsManager.DisplayEdgeToEdge = value;
+                    _insetsManager.DisplayEdgeToEdgePreference = value;
                 }
 
                 this.RaisePropertyChanged();
@@ -129,7 +129,7 @@ namespace SafeAreaDemo.ViewModels
             {
                 _insetsManager.SafeAreaChanged += InsetsManager_SafeAreaChanged;
 
-                _displayEdgeToEdge = _insetsManager.DisplayEdgeToEdge;
+                _displayEdgeToEdge = _insetsManager.DisplayEdgeToEdgePreference;
                 _hideSystemBars = !(_insetsManager.IsSystemBarVisible ?? false);
             }
 

+ 46 - 22
src/Android/Avalonia.Android/Platform/AndroidInsetsManager.cs

@@ -17,9 +17,12 @@ namespace Avalonia.Android.Platform
 {
     internal sealed class AndroidInsetsManager : WindowInsetsAnimationCompat.Callback, IInsetsManager, IOnApplyWindowInsetsListener, ViewTreeObserver.IOnGlobalLayoutListener, IInputPane
     {
+        // For now, we check if running under net 9. TODO: remove runtime check when we target net 10
+        private static bool IsDisplayEdgeToEdgeForced = System.Environment.Version.Major >=9 && Build.VERSION.SdkInt >= (BuildVersionCodes)35;
+
         private readonly Activity _activity;
         private readonly TopLevelImpl _topLevel;
-        private bool _displayEdgeToEdge;
+        private bool _displaysEdgeToEdge;
         private bool? _systemUiVisibility;
         private SystemBarTheme? _statusBarTheme;
         private bool? _isDefaultSystemBarLightTheme;
@@ -27,6 +30,7 @@ namespace Avalonia.Android.Platform
         private InputPaneState _state;
         private Rect _previousRect;
         private Insets? _previousImeInset;
+        private bool _displayEdgeToEdgePreference;
         private readonly bool _usesLegacyLayouts;
 
         private AndroidWindow Window => _activity.Window ?? throw new InvalidOperationException("Activity.Window must be set."); 
@@ -50,29 +54,42 @@ namespace Avalonia.Android.Platform
             }
         }
 
-        public bool DisplayEdgeToEdge
+        public bool DisplayEdgeToEdgePreference
         {
-            get => _displayEdgeToEdge;
+            get => _displayEdgeToEdgePreference;
             set
             {
-                _displayEdgeToEdge = value;
+                _displayEdgeToEdgePreference = value;
 
-                if (OperatingSystem.IsAndroidVersionAtLeast(28) && Window.Attributes is { } attributes)
-                {
-                    attributes.LayoutInDisplayCutoutMode = value ? LayoutInDisplayCutoutMode.ShortEdges : LayoutInDisplayCutoutMode.Default;
-                }
+               UpdateDisplayEdgeToEgdeState();
+            }
+        }
 
-                WindowCompat.SetDecorFitsSystemWindows(Window, !value);
+        private void UpdateDisplayEdgeToEgdeState()
+        {
+            if (IsDisplayEdgeToEdgeForced)
+            {
+                _displaysEdgeToEdge = true;
+                return;
+            }
 
-                if (value)
-                {
-                    Window.AddFlags(WindowManagerFlags.TranslucentStatus);
-                    Window.AddFlags(WindowManagerFlags.TranslucentNavigation);
-                }
-                else
-                {
-                    SystemBarColor = _systemBarColor;
-                }
+            _displaysEdgeToEdge = _displayEdgeToEdgePreference;
+
+            if (OperatingSystem.IsAndroidVersionAtLeast(28) && Window.Attributes is { } attributes)
+            {
+                attributes.LayoutInDisplayCutoutMode = _displayEdgeToEdgePreference ? LayoutInDisplayCutoutMode.ShortEdges : LayoutInDisplayCutoutMode.Default;
+            }
+
+            WindowCompat.SetDecorFitsSystemWindows(Window, !_displayEdgeToEdgePreference);
+
+            if (_displayEdgeToEdgePreference)
+            {
+                Window.AddFlags(WindowManagerFlags.TranslucentStatus);
+                Window.AddFlags(WindowManagerFlags.TranslucentNavigation);
+            }
+            else
+            {
+                SystemBarColor = _systemBarColor;
             }
         }
 
@@ -89,7 +106,7 @@ namespace Avalonia.Android.Platform
                 _activity.Window?.DecorView.ViewTreeObserver?.AddOnGlobalLayoutListener(this);
             }
 
-            DisplayEdgeToEdge = false;
+            DisplayEdgeToEdgePreference = false;
 
             ViewCompat.SetWindowInsetsAnimationCallback(Window.DecorView, this);
         }
@@ -105,11 +122,11 @@ namespace Avalonia.Android.Platform
                     var renderScaling = _topLevel.RenderScaling;
 
                     var inset = insets.GetInsets(
-                        _displayEdgeToEdge ?
+                        DisplaysEdgeToEdge ?
                             WindowInsetsCompat.Type.StatusBars() | WindowInsetsCompat.Type.NavigationBars() |
                             WindowInsetsCompat.Type.DisplayCutout() : 0);
 
-                    return new Thickness(inset.Left / renderScaling,
+                   return new Thickness(inset.Left / renderScaling,
                         inset.Top / renderScaling,
                         inset.Right / renderScaling,
                         inset.Bottom / renderScaling);
@@ -264,7 +281,10 @@ namespace Avalonia.Android.Platform
             {
                 _systemBarColor = value;
 
-                if (_systemBarColor is { } color && !_displayEdgeToEdge && _activity.Window != null)
+                if (IsDisplayEdgeToEdgeForced)
+                    return;
+
+                if (_systemBarColor is { } color && !_displaysEdgeToEdge && _activity.Window != null)
                 {
                     _activity.Window.ClearFlags(WindowManagerFlags.TranslucentStatus);
                     _activity.Window.ClearFlags(WindowManagerFlags.TranslucentNavigation);
@@ -282,6 +302,10 @@ namespace Avalonia.Android.Platform
             }
         }
 
+        public bool DisplayEdgeToEdge { get => DisplaysEdgeToEdge; set => DisplayEdgeToEdgePreference = value; }
+
+        public bool DisplaysEdgeToEdge => _displaysEdgeToEdge;
+
         internal void ApplyStatusBarState()
         {
             IsSystemBarVisible = _systemUiVisibility;

+ 16 - 1
src/Avalonia.Controls/Platform/IInsetsManager.cs

@@ -17,8 +17,20 @@ namespace Avalonia.Controls.Platform
         /// <summary>
         /// Gets or sets whether the window draws edge to edge. behind any visible system bars.
         /// </summary>
+        bool DisplayEdgeToEdgePreference { get; set; }
+
+
+        /// <summary>
+        /// Gets or sets whether the window draws edge to edge. behind any visible system bars.
+        /// </summary>
+        [Obsolete("Use DisplayEdgeToEdgePreference")]
         bool DisplayEdgeToEdge { get; set; }
 
+        /// <summary>
+        /// Gets whether the window is currently displaying edge to edge.
+        /// </summary>
+        bool DisplaysEdgeToEdge { get; }
+
         /// <summary>
         /// Gets the current safe area padding.
         /// </summary>
@@ -39,9 +51,12 @@ namespace Avalonia.Controls.Platform
     public abstract class InsetsManagerBase : IInsetsManager
     {
         public virtual bool? IsSystemBarVisible { get; set; }
-        public virtual bool DisplayEdgeToEdge { get; set; }
+        public virtual bool DisplayEdgeToEdgePreference { get; set; }
+        public virtual bool DisplayEdgeToEdge { get => DisplaysEdgeToEdge; set => DisplayEdgeToEdgePreference = value; }
         public virtual Thickness SafeAreaPadding { get; protected set; }
         public virtual Color? SystemBarColor { get; set; }
+        public virtual bool DisplaysEdgeToEdge => DisplayEdgeToEdgePreference;
+
         public event EventHandler<SafeAreaChangedArgs>? SafeAreaChanged;
 
         protected void OnSafeAreaChanged(SafeAreaChangedArgs eventArgs)

+ 1 - 1
src/Browser/Avalonia.Browser/BrowserInsetsManager.cs

@@ -18,7 +18,7 @@ namespace Avalonia.Browser
             }
         }
 
-        public override bool DisplayEdgeToEdge { get; set; }
+        public override bool DisplayEdgeToEdgePreference { get; set; }
 
         public override Thickness SafeAreaPadding
         {

+ 1 - 1
src/iOS/Avalonia.iOS/InsetsManager.cs

@@ -35,7 +35,7 @@ internal class InsetsManager : InsetsManagerBase
     }
     public event EventHandler<bool>? DisplayEdgeToEdgeChanged;
 
-    public override bool DisplayEdgeToEdge
+    public override bool DisplayEdgeToEdgePreference
     {
         get => _displayEdgeToEdge;
         set