Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 36 additions & 1 deletion maui/src/Core/WindowOverlay/WindowOverlay.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,24 @@ internal partial class SfWindowOverlay
/// <returns></returns>
internal virtual WindowOverlayStack CreateStack(Context context)
{
// Prefer creating the overlay stack via the MAUI handler so gesture/touch plumbing is wired.
WindowOverlayStack? windowOverlayStack = null;

if (_window is not null && _window.Handler is not null)
{
IMauiContext? mauiContext = _window.Handler.MauiContext;
if (mauiContext is not null)
{
windowOverlayStack = (WindowOverlayStack?)_overlayStackView?.ToPlatform(mauiContext);
windowOverlayStack = _overlayStackView != null ? (WindowOverlayStack?)_overlayStackView.ToPlatform(mauiContext) : null;
}
}

// Fallback to HostMauiContext for native embedding (no MAUI Window).
if (windowOverlayStack == null && WindowOverlayHelper.HostMauiContext != null)
{
windowOverlayStack = _overlayStackView != null ? (WindowOverlayStack?)_overlayStackView.ToPlatform(WindowOverlayHelper.HostMauiContext) : null;
}

return windowOverlayStack is not null ? windowOverlayStack : new WindowOverlayStack(context);
}

Expand Down Expand Up @@ -251,6 +259,33 @@ internal bool AddToOverlay(MauiView childView)
}
}
}
else
{
// Native embedding path: no MAUI Window, use host Activity and IMauiContext set by the embedding app.
var activity = WindowOverlayHelper.HostActivity;
_density = WindowOverlayHelper._density;
_rootView = WindowOverlayHelper._platformRootView;
if (_rootView != null && activity != null)
{
_overlayStack = CreateStack(activity);
_windowManager = activity.WindowManager;
if (_overlayStack != null)
{
_overlayStack.LayoutChange += OnOverlayStackLayoutChange;
if (this._windowManagerLayoutParams == null)
{
this.GetWindowManagerLayoutParams();
}

// Prefer an existing native view if handler already realized.
if (WindowOverlayHelper.HostMauiContext != null)
{
_overlayContent = childView.ToPlatform(WindowOverlayHelper.HostMauiContext);
return true;
}
}
}
}

return false;
}
Expand Down
42 changes: 31 additions & 11 deletions maui/src/Core/WindowOverlay/WindowOverlay.iOS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ internal partial class SfWindowOverlay
{
#region Fields

internal static IMauiContext? MauiContext { get; set; }

internal static UIWindow? Window { get; set; }

UIView? _rootView;
WindowOverlayStack? _overlayStack;
UIView? _overlayContent;
Expand All @@ -23,23 +27,21 @@ internal partial class SfWindowOverlay
internal virtual WindowOverlayStack CreateStack()
{
WindowOverlayStack? windowOverlayStack = null;
if (_window is not null && _window.Handler is not null)
IMauiContext? context = _window?.Handler?.MauiContext ?? SfWindowOverlay.MauiContext;
if (context is not null)
{
IMauiContext? context = _window.Handler.MauiContext;
if (context is not null)
{
windowOverlayStack = (WindowOverlayStack?)_overlayStackView?.ToPlatform(context);
windowOverlayStack = (WindowOverlayStack?)_overlayStackView?.ToPlatform(context);

if (windowOverlayStack is not null && _overlayStackView is not null)
{
windowOverlayStack._canHandleTouch = !_overlayStackView.canHandleTouch;
}
if (windowOverlayStack is not null && _overlayStackView is not null)
{
windowOverlayStack._canHandleTouch = !_overlayStackView.canHandleTouch;
}
}

return windowOverlayStack is not null ? windowOverlayStack : new WindowOverlayStack();
return windowOverlayStack is not null ? windowOverlayStack : new WindowOverlayStack();
}


/// <summary>
/// Adds or updates the child layout absolutely to the overlay stack.
/// </summary>
Expand Down Expand Up @@ -171,6 +173,22 @@ internal void RemoveOverlay()
internal bool AddToOverlay(MauiView childView)
{
_window = WindowOverlayHelper._window;

// Native embedding path when MAUI Window is not yet available.
if ((_window == null || _window.Content == null) && SfWindowOverlay.MauiContext != null && SfWindowOverlay.Window != null)
{
_rootView = SfWindowOverlay.Window;
_overlayStack ??= CreateStack();
if (_overlayStack != null)
{
_overlayStack.AutoresizingMask = UIViewAutoresizing.All;
_overlayContent = childView.ToPlatform(SfWindowOverlay.MauiContext);
return true;
}

return false;
}

if (_window is not null && _window.Content is not null)
{
_rootView = WindowOverlayHelper._platformRootView;
Expand Down Expand Up @@ -260,7 +278,9 @@ internal void PositionOverlayContent(double x = 0, double y = 0)
keyWindow = UIApplication.SharedApplication.KeyWindow!;
}

if (_rootView != keyWindow)
// Only switch to the keyWindow if we actually found one. For native embedding scenarios.
// the initial rootView may be provided via SfWindowOverlay.Window and keyWindow can be null.
if (keyWindow != null && _rootView != keyWindow)
{
_rootView = keyWindow;
}
Expand Down
41 changes: 40 additions & 1 deletion maui/src/Core/WindowOverlay/WindowOverlayHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,11 @@ internal static IWindow? _window
/// <summary>
/// Gets the device density.
/// </summary>
internal static float _density => _window is not null ? _window.RequestDisplayDensity() : 1f;
#if ANDROID
internal static float _density => _window != null ? _window.RequestDisplayDensity() : (HostActivity != null ? HostActivity.Resources?.DisplayMetrics?.Density ?? 1f : 1f);
#else
internal static float _density => _window != null ? _window.RequestDisplayDensity() : 1f;
#endif

/// <summary>
/// Gets the root view of the device.
Expand All @@ -48,6 +52,16 @@ internal static IWindow? _window

#if ANDROID

/// <summary>
/// Optional host Activity for embedding scenarios where MAUI Window is not available.
/// </summary>
internal static Activity? HostActivity;

/// <summary>
/// Optional host IMauiContext for embedding scenarios when converting views without a Window.
/// </summary>
internal static IMauiContext? HostMauiContext;

/// <summary>
/// Gets the decor view frame.
/// </summary>
Expand Down Expand Up @@ -155,6 +169,20 @@ internal static IWindow? _window
}
#endif
}
#if ANDROID
// Fallback for native embedding: derive root from host Activity when MAUI Window is unavailable.
else if (rootView == null && HostActivity != null)
{
try
{
rootView = HostActivity.FindViewById(Android.Resource.Id.Content) as ViewGroup;
}
catch
{
rootView = null;
}
}
#endif

return rootView;
}
Expand All @@ -178,6 +206,17 @@ internal static IWindow? _window
return platformActivity.Window;
}

// Fallback for native embedding: use HostActivity if available.
else if (HostActivity != null)
{
if (HostActivity.WindowManager != null && HostActivity.WindowManager.DefaultDisplay != null)
{
return HostActivity.Window;
}

return null;
}

return null;
}

Expand Down
12 changes: 11 additions & 1 deletion maui/src/Popup/Helpers/PopupExtension/PopupExtension.Android.cs
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,17 @@ internal static Rect GetRelativeViewBounds(this SfPopup popup, MauiView relative
{
int[] relativeViewOrigin = new int[2];
nativeRelativeView.GetLocationInWindow(relativeViewOrigin);
relativeViewOrigin[1] = PopupExtension.GetLocationInApp(relativeView);

if (WindowOverlayHelper._decorViewContent is PlatformView decorView && nativeRelativeView.RootView == decorView)
{
relativeViewOrigin[1] = PopupExtension.GetLocationInApp(relativeView);
}
else
{
// 1008572: Popup relative position is incorrect when opening a popup within another popup on Android.
relativeViewOrigin[1] = (int)(relativeViewOrigin[1] / WindowOverlayHelper._density);
}

return new Rect(relativeViewOrigin[0] / WindowOverlayHelper._density, relativeViewOrigin[1], nativeRelativeView.Width / WindowOverlayHelper._density, nativeRelativeView.Height / WindowOverlayHelper._density);
}
else
Expand Down
Loading