KEMBAR78
Implement SafeAreaEdges property and per-edge safe area control for Android by NirmalKumarYuvaraj · Pull Request #31022 · dotnet/maui · GitHub
Skip to content

Conversation

NirmalKumarYuvaraj
Copy link
Contributor

@NirmalKumarYuvaraj NirmalKumarYuvaraj commented Aug 5, 2025

Note

Are you waiting for the changes in this PR to be merged?
It would be very helpful if you could test the resulting artifacts from this PR and let us know in a comment if this change resolves your issue. Thank you!

Description of Change

This pull request introduces a unified and optimized approach for handling safe area insets and keyboard visibility across Android platform views in the codebase. The changes add a new SafeAreaHandler class, refactor ContentViewGroup and LayoutViewGroup to use this handler, and implement supporting types and extension methods for safe area calculations. The main goal is to ensure consistent, performant, and keyboard-aware safe area handling for layouts, reducing repeated hierarchy traversals and improving maintainability.

Safe Area Handling Improvements

  • Added the new SafeAreaHandler class (SafeAreaHandler.cs) to encapsulate shared logic for safe area and keyboard inset handling, including caching, hierarchy traversal optimizations, and a unified window insets listener.
  • Refactored ContentViewGroup and LayoutViewGroup to instantiate and use SafeAreaHandler, including setup of window insets listeners and safe area adjustment logic in their constructors and OnLayout methods. [1] [2] [3] [4]

Supporting Types and Extensions

  • Introduced the SafeAreaPadding record struct and WindowInsetsExtensions static class for safe area and keyboard inset calculations, conversion, and rectangle adjustment.

Dependency Updates

  • Added AndroidX.Core.View using statements to affected files to support new window insets APIs. [1] [2]

These changes collectively provide a robust foundation for safe area and keyboard-aware layout on Android, making it easier to maintain and extend in the future.

Issues Fixed

Fixes # https://devdiv.visualstudio.com/DevDiv/_workitems/edit/2433909

Output

Android.mov

@dotnet-policy-service dotnet-policy-service bot added community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration labels Aug 5, 2025
@PureWeen PureWeen added this to the .NET 10.0-rc1 milestone Aug 5, 2025
@albyrock87
Copy link
Contributor

Thank you so much for this effort!
I have some concerns regarding performance given this will be called on every node and it involves a lot of JNI calls.
Do you think we could move the majority of the logic on the Java side?

@PureWeen PureWeen moved this from Todo to In Progress in MAUI SDK Ongoing Aug 17, 2025
@PureWeen PureWeen modified the milestones: .NET 10.0-rc1, .NET 10.0-rc2 Aug 17, 2025
@NirmalKumarYuvaraj NirmalKumarYuvaraj marked this pull request as ready for review August 18, 2025 12:18
@Copilot Copilot AI review requested due to automatic review settings August 18, 2025 12:18
@NirmalKumarYuvaraj NirmalKumarYuvaraj requested a review from a team as a code owner August 18, 2025 12:18
Copy link
Contributor

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This pull request implements a comprehensive safe area handling system for Android platform in .NET MAUI, introducing per-edge safe area control and keyboard awareness. The implementation adds a centralized SafeAreaHandler class to manage safe area insets consistently across different view types while optimizing performance through caching and hierarchy traversal optimizations.

  • Introduces unified safe area handling with SafeAreaHandler class for consistent behavior across ContentViewGroup and LayoutViewGroup
  • Adds per-edge safe area control through new SafeAreaPadding record and WindowInsetsExtensions
  • Integrates keyboard-aware layout adjustments that respond to IME visibility changes

Reviewed Changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
SafeAreaPadding.cs New record struct for representing safe area padding with conversion utilities
SafeAreaHandler.cs Core safe area management class with caching, hierarchy checks, and window insets handling
MauiScrollView.cs Minor addition of AndroidX.Core.View using statement and null check
LayoutViewGroup.cs Integration of SafeAreaHandler with window insets listener setup and safe area adjustments
ContentViewGroup.cs Integration of SafeAreaHandler with window insets listener setup and safe area adjustments
Comments suppressed due to low confidence (2)

@jsuarezruiz
Copy link
Contributor

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 3 pipeline(s).

Copy link
Contributor

@jsuarezruiz jsuarezruiz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are the tests to validate the changes, right?
#30908

Could we expand it to support more edge cases? I would include more tests like:

  • SafeAreaBorderOrientationPortraitToLandscape - Tests orientation change from portrait to landscape, verifying that the safe area adapts, the border dimensions change, and insets adjust on notched devices.
  • SafeAreaBorderOrientationLandscapeToPortrait - Tests orientation change from landscape to portrait, ensuring the safe area reverts correctly and border dimensions differ between orientations.
  • SafeAreaBorderMultipleOrientationChanges - Tests multiple sequential orientation changes (portrait to landscape and back), verifying border visibility, positioning consistency within the same orientation (with tolerance), and overall stability.
  • SafeAreaBorderSoftInputBehavior - Tests soft input (keyboard) behavior with bottom edge set to SoftInput, checking that the border shrinks when the keyboard appears and returns to original size after dismissal.
  • SafeAreaBorderSoftInputWithOrientationChange - Tests soft input with orientation change (portrait to landscape) while keyboard is visible, ensuring the border maintains visibility and dimensions differ between orientations.

@github-project-automation github-project-automation bot moved this from In Progress to Changes Requested in MAUI SDK Ongoing Sep 1, 2025
@PureWeen
Copy link
Member

PureWeen commented Sep 2, 2025

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 3 pipeline(s).

Copy link
Member

@PureWeen PureWeen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I still need to review this a little bit deeper but I do still wonder about @albyrock87 's comment here

#31022 (comment)

I wonder about the approach here with storing the safea area into separate handlers and then modifying the arrange pass.

In theory could we just have a global handler that sets the padding on the view?

Basically what I've done to fix the safearea on various views for edge to edge is just set the padding inside the windowinset listener

image

could we take the same approach here? Like, we just have a window listener applied to ContentViewGroup and LayoutViewGroup and then inside the "ApplyWindowLIstener" it extracts the safeareas and sets the padding on the views.

If the padding is set on the views than the measure and arrange passes will just work. The main reason we don't do this approach on iOS (AFAIK) is that iOS doesn't really have a concept of "padding" you can set on views, you always just fake the padding inside LayoutSubviews.

Microsoft.Maui.LifecycleEvents.AndroidLifecycle.OnKeyMultiple
Microsoft.Maui.LifecycleEvents.AndroidLifecycle.OnKeyShortcut
Microsoft.Maui.LifecycleEvents.AndroidLifecycle.OnKeyUp
Microsoft.Maui.Platform.IHandleWindowInsets
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep these internal for now

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, marked it as internal.

/// Gets the shared GlobalWindowInsetListener instance for this activity.
/// This ensures all views use the same listener instance for coordinated inset management.
/// </summary>
public GlobalWindowInsetListener GlobalWindowInsetListener =>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make this internal

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PureWeen , Done, marked it as internal.

@PureWeen
Copy link
Member

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 3 pipeline(s).

@PureWeen
Copy link
Member

/azp run

@PureWeen
Copy link
Member

/backport to release/10.0.1xx-rc2

@azure-pipelines
Copy link

Azure Pipelines successfully started running 3 pipeline(s).

@github-actions
Copy link
Contributor

Started backporting to release/10.0.1xx-rc2: https://github.com/dotnet/maui/actions/runs/18048977023

Updated assertion message for clarity and added conditional compilation for return statement.
@PureWeen
Copy link
Member

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 3 pipeline(s).

Added comments regarding test behavior differences between headless and non-headless modes for Android.
@PureWeen
Copy link
Member

/azp run

@PureWeen
Copy link
Member

/backport to release/10.0.1xx-rc2

@azure-pipelines
Copy link

Azure Pipelines successfully started running 3 pipeline(s).

@github-actions
Copy link
Contributor

Started backporting to release/10.0.1xx-rc2: https://github.com/dotnet/maui/actions/runs/18051590261

Removed commented-out code regarding test behavior for headless vs non-headless view positioning. Updated test method for better clarity.
@PureWeen
Copy link
Member

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 3 pipeline(s).

@PureWeen
Copy link
Member

/backport to release/10.0.1xx-rc2

@github-actions
Copy link
Contributor

Started backporting to release/10.0.1xx-rc2: https://github.com/dotnet/maui/actions/runs/18052761878

@PureWeen
Copy link
Member

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 3 pipeline(s).

@PureWeen
Copy link
Member

/backport to release/10.0.1xx-rc2

@github-actions
Copy link
Contributor

Started backporting to release/10.0.1xx-rc2: https://github.com/dotnet/maui/actions/runs/18057314724

@rmarinho rmarinho merged commit 0371d31 into dotnet:net10.0 Sep 28, 2025
151 of 153 checks passed
@github-project-automation github-project-automation bot moved this from Changes Requested to Done in MAUI SDK Ongoing Sep 28, 2025
@PureWeen PureWeen mentioned this pull request Oct 21, 2025
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community ✨ Community Contribution p/0 Work that we can't release without partner/syncfusion Issues / PR's with Syncfusion collaboration

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants