Skip to content

[Android] - Implement WindowInsetListener for per coordinator layout#31898

Closed
NirmalKumarYuvaraj wants to merge 6 commits intodotnet:mainfrom
NirmalKumarYuvaraj:SafeAreaFollowUp
Closed

[Android] - Implement WindowInsetListener for per coordinator layout#31898
NirmalKumarYuvaraj wants to merge 6 commits intodotnet:mainfrom
NirmalKumarYuvaraj:SafeAreaFollowUp

Conversation

@NirmalKumarYuvaraj
Copy link
Contributor

@NirmalKumarYuvaraj NirmalKumarYuvaraj commented Oct 7, 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 significant improvements to how safe area insets and window inset listeners are managed for Android in the MAUI codebase. The main enhancement is a new registry system for tracking CoordinatorLayout instances and their associated GlobalWindowInsetListeners, allowing for more precise and leak-free management of safe area insets, especially in complex navigation scenarios. Several components now use local listeners instead of a global one, and cleanup logic has been improved to avoid memory leaks.

Safe area and window inset management improvements:

  • Introduced a static registry in GlobalWindowInsetListener to track CoordinatorLayout instances and their local listeners, enabling views to find the appropriate listener for safe area updates. This includes new helper methods for registering, unregistering, and cleaning up listeners and layouts.
  • Updated ShellContentFragment and ShellSectionRenderer to use local GlobalWindowInsetListener instances per CoordinatorLayout, including setup and cleanup logic to avoid cross-contamination and memory leaks.
  • Refactored ViewHandler.Android.cs to use the new registry-based approach for finding the correct GlobalWindowInsetListener for a view, replacing the previous context-based lookup and simplifying the logic for resetting safe areas.
  • Simplified modal handling by removing the creation and cleanup of separate GlobalWindowInsetListener instances for modals, relying on the new registry system instead.
  • Updated ContentViewGroup and WindowHandler.Android.cs to use the new registry-based listener lookup and clarified cleanup responsibilities when disconnecting handlers.

These changes collectively make the handling of safe area insets more robust, modular, and less prone to memory leaks or incorrect inset application in complex navigation scenarios.

Fixes #

@dotnet-policy-service dotnet-policy-service bot added the community ✨ Community Contribution label Oct 7, 2025
@dotnet-policy-service
Copy link
Contributor

Hey there @@NirmalKumarYuvaraj! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed.

@dotnet-policy-service dotnet-policy-service bot added the partner/syncfusion Issues / PR's with Syncfusion collaboration label Oct 7, 2025
@jsuarezruiz
Copy link
Contributor

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 3 pipeline(s).

listener.RegisterCoordinatorLayout(coordinatorLayout);

// Set up event handlers for attach/detach
coordinatorLayout.ViewAttachedToWindow += (sender, e) =>
Copy link
Contributor

Choose a reason for hiding this comment

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

Lambda captures create strong references and there is no cleanup/unsubscribe mechanism. Could improve it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@jsuarezruiz , I have updated changes. please let me know if you have any concerns.

@NirmalKumarYuvaraj NirmalKumarYuvaraj marked this pull request as ready for review October 29, 2025 07:45
Copilot AI review requested due to automatic review settings October 29, 2025 07:45
Copy link
Contributor

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 PR refactors the Android GlobalWindowInsetListener architecture from a global activity-level pattern to a localized CoordinatorLayout-based approach. Instead of having a single shared listener instance per activity, each CoordinatorLayout now manages its own listener instance which is tracked in a static registry.

Key changes:

  • Replaced global activity-level listener with local per-CoordinatorLayout listeners tracked in a static registry
  • Added FindListenerForView() to locate the appropriate listener by traversing view hierarchy
  • Updated all call sites to use FindListenerForView() instead of Context.GetGlobalWindowInsetListener()

Reviewed Changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
GlobalWindowInsetListener.cs Core refactoring: added static registry, view hierarchy lookup methods, and CoordinatorLayout management
MauiAppCompatActivity.cs Removed activity-level global listener property and lifecycle management
NavigationRootManager.cs Changed to create and manage local listener for NavigationRootManager's CoordinatorLayout
SafeAreaExtensions.cs Updated to use FindListenerForView instead of GetGlobalWindowInsetListener
MauiScrollView.cs Updated to use FindListenerForView for configuration changes
LayoutViewGroup.cs Updated to use FindListenerForView for configuration changes
ContentViewGroup.cs Updated to use FindListenerForView for configuration changes
ViewHandler.Android.cs Updated MapSafeAreaEdges to use FindListenerForView
WindowHandler.Android.cs Added cleanup comment for local listener management
ModalNavigationManager.Android.cs Removed separate modal listener management (now uses registry approach)
ShellSectionRenderer.cs Added local listener setup and cleanup for Shell sections
ShellContentFragment.cs Added local listener setup and cleanup for Shell content fragments

Comment on lines +80 to +81
GlobalWindowInsetListener _localInsetListener;
CoordinatorLayout _managedCoordinatorLayout;
Copy link

Copilot AI Oct 29, 2025

Choose a reason for hiding this comment

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

These fields should be marked with ? to indicate nullability since they are assigned after construction and set to null in Destroy(). This should be GlobalWindowInsetListener? _localInsetListener; and CoordinatorLayout? _managedCoordinatorLayout;.

Suggested change
GlobalWindowInsetListener _localInsetListener;
CoordinatorLayout _managedCoordinatorLayout;
GlobalWindowInsetListener? _localInsetListener;
CoordinatorLayout? _managedCoordinatorLayout;

Copilot uses AI. Check for mistakes.
Comment on lines +77 to +78
GlobalWindowInsetListener _localInsetListener;
CoordinatorLayout _managedCoordinatorLayout;
Copy link

Copilot AI Oct 29, 2025

Choose a reason for hiding this comment

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

These fields should be marked with ? to indicate nullability since they are assigned conditionally in OnCreateView() and set to null in Destroy(). This should be GlobalWindowInsetListener? _localInsetListener; and CoordinatorLayout? _managedCoordinatorLayout;.

Suggested change
GlobalWindowInsetListener _localInsetListener;
CoordinatorLayout _managedCoordinatorLayout;
GlobalWindowInsetListener? _localInsetListener;
CoordinatorLayout? _managedCoordinatorLayout;

Copilot uses AI. Check for mistakes.
Comment on lines +28 to +29
// No locking needed since this runs on UI thread
static readonly List<CoordinatorLayoutEntry> _registeredCoordinatorLayouts = new();
Copy link

Copilot AI Oct 29, 2025

Choose a reason for hiding this comment

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

The comment assumes this always runs on the UI thread, but there's no enforcement. Consider adding thread safety or documenting the threading requirements more explicitly, especially since this is a static shared resource that could potentially be accessed from multiple contexts.

Copilot uses AI. Check for mistakes.
@PureWeen PureWeen changed the base branch from net10.0 to main October 29, 2025 12:12
@PureWeen
Copy link
Member

/rebase

@jsuarezruiz
Copy link
Contributor

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 3 pipeline(s).

/// <summary>
/// Checks if a view is contained within the specified layout's hierarchy
/// </summary>
static bool IsViewContainedIn(AView view, ViewGroup layout)
Copy link
Contributor

Choose a reason for hiding this comment

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

Can trminate early if another CoordinatorLayout is found in the hierarchy that is not the target layout:

if (parent is CoordinatorLayout && parent != layout)
     return false;

@PureWeen
Copy link
Member

Moving this PR over to here
#32278

@PureWeen PureWeen closed this Oct 30, 2025
@github-actions github-actions bot locked and limited conversation to collaborators Nov 30, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

community ✨ Community Contribution partner/syncfusion Issues / PR's with Syncfusion collaboration platform/android

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants