Fix insets on android 15 (#18844)

* fix insets on android 15

* add api diff

* fix nit
This commit is contained in:
Emmanuel Hansen
2025-06-05 15:26:33 +00:00
committed by GitHub
parent 72fa47157c
commit 2dc808f3e8
7 changed files with 81 additions and 30 deletions
+12
View File
@@ -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
View File
@@ -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;
};
}
@@ -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);
}
@@ -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;
@@ -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)
@@ -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
View File
@@ -35,7 +35,7 @@ internal class InsetsManager : InsetsManagerBase
}
public event EventHandler<bool>? DisplayEdgeToEdgeChanged;
public override bool DisplayEdgeToEdge
public override bool DisplayEdgeToEdgePreference
{
get => _displayEdgeToEdge;
set