Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
1c03f24
Sandbox test sample
Tamilarasan-Paranthaman Mar 2, 2026
81484c1
Android Shell Handler
Tamilarasan-Paranthaman Mar 2, 2026
79ade1d
Update ShellFlyoutTemplatedContentRenderer.cs
Tamilarasan-Paranthaman Mar 3, 2026
bdf44a9
Fix shell section switching issue
Tamilarasan-Paranthaman Mar 4, 2026
c42f819
Fix shell handler issues
Tamilarasan-Paranthaman Mar 10, 2026
c794b4d
Updating Sandbox test sample
Tamilarasan-Paranthaman Mar 10, 2026
c0508ec
Phase 2: Fix shell handler issues
Tamilarasan-Paranthaman Mar 10, 2026
73baa22
Phase 3: Fixed Shell item handler issues
Tamilarasan-Paranthaman Mar 11, 2026
ad69796
Phase 4: Fix Shell handler issues
Tamilarasan-Paranthaman Mar 12, 2026
8bb51b3
Phase 5: Fix Shell item and section issues
Tamilarasan-Paranthaman Mar 13, 2026
b46cf84
Update ShellHandler.Android.cs
Tamilarasan-Paranthaman Mar 16, 2026
8d533cc
Revamp Shell Structure
Tamilarasan-Paranthaman Mar 18, 2026
ea93acb
Fix ShellSection issues
Tamilarasan-Paranthaman Mar 23, 2026
8653108
Fix Shell issues
Tamilarasan-Paranthaman Mar 24, 2026
0babcb3
Implemented TabbedViewManager
Tamilarasan-Paranthaman Mar 25, 2026
1d35079
Fix Shell related issues and refactor code
Tamilarasan-Paranthaman Mar 26, 2026
1aa6633
Consolidate Android Shell handler mappers
Tamilarasan-Paranthaman Mar 26, 2026
8533326
Refactor code and sync changes with the Unshipped file
Tamilarasan-Paranthaman Mar 26, 2026
a382266
Fix Shell tab issues
Tamilarasan-Paranthaman Mar 27, 2026
f9d0d88
Replace PropertyChanged with mapper
Tamilarasan-Paranthaman Mar 30, 2026
6703461
Updated sandbox test sample
Tamilarasan-Paranthaman Mar 30, 2026
65877c4
Fix issues in Shell handler
Tamilarasan-Paranthaman Mar 31, 2026
4c2216c
Revert sandbox sample changes
Tamilarasan-Paranthaman Mar 31, 2026
0bdb788
Enable SH through build configuration
Tamilarasan-Paranthaman Mar 31, 2026
da35cc9
Update StackNavigationManager.cs
Tamilarasan-Paranthaman Apr 1, 2026
b16d7eb
Enable nullable annotations for Shell handlers
Tamilarasan-Paranthaman Apr 2, 2026
b51c4c8
Update PublicAPI.Unshipped.txt
Tamilarasan-Paranthaman Apr 6, 2026
cd5971e
Fix issues in TabbedPage
Tamilarasan-Paranthaman Apr 9, 2026
2d35275
Resave incorrect snapshots
Tamilarasan-Paranthaman Apr 9, 2026
e84238d
Add badge support in the handler
Tamilarasan-Paranthaman Apr 17, 2026
610f287
Optimize the shell handler
Tamilarasan-Paranthaman Apr 17, 2026
87122df
Addressed concerns.
Vignesh-SF3580 Apr 22, 2026
cc060f1
Update TabbedViewManager.cs
Vignesh-SF3580 Apr 24, 2026
6decae5
Update ActionModeMenuShouldNotBeVisibleAfterSwitchingTab.png
Tamilarasan-Paranthaman Apr 27, 2026
ac107d7
Fix shell handler test failures
Tamilarasan-Paranthaman Apr 29, 2026
9b063f7
Update BackButtonBehavior_IsVisible_False_ProgrammaticNavStillWorks.png
Tamilarasan-Paranthaman Apr 30, 2026
62bf556
Update TabBarShouldBeVisibleAfterNavigatingFromModalViaGoToAsync.png
Tamilarasan-Paranthaman May 14, 2026
c5c2f2f
Fix migration impact for custom Shell renderer users
Tamilarasan-Paranthaman May 22, 2026
355f9d0
ShellHandler build and Lane setup
Ahamed-Ali May 25, 2026
8407cf7
modified
Ahamed-Ali May 25, 2026
6b80fb1
Separate build for Shell Handlers Android
Ahamed-Ali May 29, 2026
2d5b57e
Resave incorrect snapshots
Tamilarasan-Paranthaman Jun 3, 2026
e79c77c
Restrict two UI tests on android.
Vignesh-SF3580 Jun 4, 2026
6fc9502
Make Android Shell Handler by default
Tamilarasan-Paranthaman Jun 4, 2026
886d1af
Changed ShellRenderer as separate lane and use Shellhandler as default
Ahamed-Ali Jun 4, 2026
24fd8c4
Revert the separate pipeline for Shell Renderer
Tamilarasan-Paranthaman Jun 5, 2026
ca97deb
Enable tests for Android Shell Handler
Tamilarasan-Paranthaman Jun 5, 2026
c51ce9d
update unshipped file
Tamilarasan-Paranthaman Jun 5, 2026
bdeacd4
Fix Shell Handler issues
Tamilarasan-Paranthaman Jun 17, 2026
f5df6cd
Fixed shell test failures
Tamilarasan-Paranthaman Jun 18, 2026
3b399f8
Resave incorrect snapshots
Tamilarasan-Paranthaman Jun 18, 2026
060b87c
Removed UseAndroidShellHandlers
Tamilarasan-Paranthaman Jun 18, 2026
04a5d27
Revert unwanted changes
Tamilarasan-Paranthaman Jun 18, 2026
0192d7c
Update TabbedViewManager.cs
Tamilarasan-Paranthaman Jun 18, 2026
6b08af0
Address handler issues
Tamilarasan-Paranthaman Jun 18, 2026
931aa5e
Address review concerns: defensive fixes
Tamilarasan-Paranthaman Jun 19, 2026
357f9a0
Add test sample
Tamilarasan-Paranthaman Jun 19, 2026
7c303c7
Fix shell handler issues
Tamilarasan-Paranthaman Jun 22, 2026
50d02f4
Resave incorrect snapshot
Tamilarasan-Paranthaman Jun 22, 2026
47a6f5d
Fix shell tab issues
Tamilarasan-Paranthaman Jun 23, 2026
8d0fdfd
Address concerns
Tamilarasan-Paranthaman Jun 23, 2026
a98dec4
Revert ITabbedView expansion
Tamilarasan-Paranthaman Jun 23, 2026
daf6e64
Refactor the code
Tamilarasan-Paranthaman Jun 23, 2026
74d7ac7
Revert unwanted changes
Tamilarasan-Paranthaman Jun 23, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ DataTemplate GetDataTemplate(int viewTypeId)

public override void OnViewRecycled(Java.Lang.Object holder)
{
if (holder is ElementViewHolder evh)
if (holder is ElementViewHolder evh && _listItems is not null)
{
// only clear out the Element if the item has been removed
bool found = false;
Expand Down Expand Up @@ -208,7 +208,9 @@ protected virtual void OnFlyoutItemsChanged(object sender, EventArgs e)
protected override void Dispose(bool disposing)
{
if (_disposed)
{
return;
}

_disposed = true;

Expand All @@ -222,8 +224,15 @@ protected override void Dispose(bool disposing)

internal void Disconnect()
{
if (_shellContext is null)
{
return;
}

if (Shell is IShellController scc)
{
scc.FlyoutItemsChanged -= OnFlyoutItemsChanged;
}

_listItems = null;
_selectedCallback = null;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
#nullable disable
using System;
using System.ComponentModel;
using System.Threading.Tasks;
using Android.Content;
using Android.Graphics.Drawables;
using Android.Hardware.Lights;
using Android.Runtime;
using Android.Util;
using Android.Views;
using Android.Widget;
using AndroidX.CoordinatorLayout.Widget;
Expand All @@ -15,12 +11,9 @@
using AndroidX.RecyclerView.Widget;
using Google.Android.Material.AppBar;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Maui.Controls.Internals;
using Microsoft.Maui.Controls.Platform.Compatibility;
using Microsoft.Maui.Layouts;
using AView = Android.Views.View;
using LP = Android.Views.ViewGroup.LayoutParams;

namespace Microsoft.Maui.Controls.Platform.Compatibility
{
public class ShellFlyoutTemplatedContentRenderer : Java.Lang.Object, IShellFlyoutContentRenderer
Expand Down Expand Up @@ -211,6 +204,7 @@ protected virtual void LoadView(IShellContext shellContext)
MauiWindowInsetListener.SetupViewWithLocalListener(coordinator, _shellFlyoutListener);

UpdateFlyoutHeaderBehavior();

_shellContext.Shell.PropertyChanged += OnShellPropertyChanged;

UpdateFlyoutBackground();
Expand Down Expand Up @@ -267,31 +261,51 @@ protected void OnElementSelected(Element element)

protected virtual void OnShellPropertyChanged(object sender, PropertyChangedEventArgs e)
{
// When using the new ShellHandler (not the compatibility ShellRenderer),
// all these properties are already handled by the handler's property mapper.
// Responding to PropertyChanged here would cause double updates.
if (_shellContext.Shell.Handler is Handlers.ShellHandler)
{
return;
}

if (e.PropertyName == Shell.FlyoutHeaderBehaviorProperty.PropertyName)
{
UpdateFlyoutHeaderBehavior();
}
else if (e.IsOneOf(
Shell.FlyoutBackgroundColorProperty,
Shell.FlyoutBackgroundProperty,
Shell.FlyoutBackgroundImageProperty,
Shell.FlyoutBackgroundImageAspectProperty))
{
UpdateFlyoutBackground();
}
else if (e.Is(Shell.FlyoutVerticalScrollModeProperty))
{
UpdateVerticalScrollMode();
}
else if (e.IsOneOf(
Shell.FlyoutHeaderProperty,
Shell.FlyoutHeaderTemplateProperty))
{
UpdateFlyoutHeader();
}
else if (e.IsOneOf(
Shell.FlyoutFooterProperty,
Shell.FlyoutFooterTemplateProperty))
{
UpdateFlyoutFooter();
}
else if (e.IsOneOf(
Shell.FlyoutContentProperty,
Shell.FlyoutContentTemplateProperty))
{
UpdateFlyoutContent();
}
}

protected virtual void UpdateFlyoutContent()
public virtual void UpdateFlyoutContent()
{
if (!_rootView.IsAlive())
return;
Expand Down Expand Up @@ -362,7 +376,7 @@ AView CreateFlyoutContent(ViewGroup rootView)
return _contentView.PlatformView;
}

protected virtual void UpdateFlyoutHeader()
public virtual void UpdateFlyoutHeader()
{
if (_headerView != null)
{
Expand All @@ -374,10 +388,7 @@ protected virtual void UpdateFlyoutHeader()
oldHeaderView.Dispose();
}

if (_flyoutHeader != null)
{
_flyoutHeader.MeasureInvalidated -= OnFlyoutHeaderMeasureInvalidated;
}
_flyoutHeader?.MeasureInvalidated -= OnFlyoutHeaderMeasureInvalidated;

_flyoutHeader = ((IShellController)_shellContext.Shell).FlyoutHeader;
if (_flyoutHeader != null)
Expand Down Expand Up @@ -414,7 +425,7 @@ void OnHeaderViewLayoutChange(object sender, AView.LayoutChangeEventArgs e)
UpdateContentPadding();
}

protected virtual void UpdateFlyoutFooter()
public virtual void UpdateFlyoutFooter()
{
if (_footerView != null)
{
Expand All @@ -427,7 +438,7 @@ protected virtual void UpdateFlyoutFooter()

var footer = ((IShellController)_shellContext.Shell).FlyoutFooter;

if (footer == null)
if (footer is null)
{
UpdateContentPadding();
return;
Expand Down Expand Up @@ -592,18 +603,17 @@ void OnFlyoutViewLayoutChanging()
}
}

void UpdateVerticalScrollMode()
public virtual void UpdateVerticalScrollMode()
{
if (_flyoutContentView is RecyclerView rv && rv.GetLayoutManager() is ScrollLayoutManager lm)
{
lm.ScrollVertically = _shellContext.Shell.FlyoutVerticalScrollMode;
}
}

protected virtual void UpdateFlyoutBackground()
public virtual void UpdateFlyoutBackground()
{
var brush = _shellContext.Shell.FlyoutBackground;

if (Brush.IsNullOrEmpty(brush))
{
var color = _shellContext.Shell.FlyoutBackgroundColor;
Expand Down Expand Up @@ -672,7 +682,7 @@ void UpdateFlyoutBgImageAsync()
});
}

protected virtual void UpdateFlyoutHeaderBehavior()
public virtual void UpdateFlyoutHeaderBehavior()
{
if (_headerView == null)
return;
Expand Down Expand Up @@ -737,8 +747,7 @@ internal void Disconnect()
if (_shellContext?.Shell != null)
_shellContext.Shell.PropertyChanged -= OnShellPropertyChanged;

if (_flyoutHeader != null)
_flyoutHeader.MeasureInvalidated -= OnFlyoutHeaderMeasureInvalidated;
_flyoutHeader?.MeasureInvalidated -= OnFlyoutHeaderMeasureInvalidated;

_flyoutHeader = null;

Expand Down Expand Up @@ -775,8 +784,7 @@ protected override void Dispose(bool disposing)
if (View != null && View is ShellFlyoutLayout sfl)
sfl.LayoutChanging -= OnFlyoutViewLayoutChanging;

if (_headerView != null)
_headerView.LayoutChange -= OnHeaderViewLayoutChange;
_headerView?.LayoutChange -= OnHeaderViewLayoutChange;

_contentView?.View = null;

Expand Down Expand Up @@ -814,8 +822,7 @@ public HeaderContainer(Context context, View view, IMauiContext mauiContext) : b

void Initialize(View view)
{
if (view != null)
view.PropertyChanged += OnViewPropertyChanged;
view?.PropertyChanged += OnViewPropertyChanged;
}

void OnViewPropertyChanged(object sender, PropertyChangedEventArgs e)
Expand Down Expand Up @@ -874,11 +881,8 @@ protected override void Dispose(bool disposing)

internal void Disconnect()
{
if (View != null)
{
View.PropertyChanged -= OnViewPropertyChanged;
View = null;
}
View?.PropertyChanged -= OnViewPropertyChanged;
View = null;
}

internal void SetFlyoutHeaderBehavior(FlyoutHeaderBehavior flyoutHeaderBehavior)
Expand Down Expand Up @@ -984,4 +988,4 @@ public override bool CanScrollVertically()
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,11 @@ class CustomFilter : Filter
{
private readonly BaseAdapter _adapter;

// Required by Android JNI bridge for native handle activation
protected CustomFilter(IntPtr javaReference, global::Android.Runtime.JniHandleOwnership transfer) : base(javaReference, transfer)
{
}

public CustomFilter(BaseAdapter adapter)
{
_adapter = adapter;
Expand All @@ -169,7 +174,7 @@ protected override FilterResults PerformFiltering(ICharSequence constraint)

protected override void PublishResults(ICharSequence constraint, FilterResults results)
{
_adapter.NotifyDataSetChanged();
_adapter?.NotifyDataSetChanged();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ public ShellToolbarAppearanceTracker(IShellContext shellContext)

public virtual void SetAppearance(AToolbar toolbar, IShellToolbarTracker toolbarTracker, ShellAppearance appearance)
{
if (appearance is null)
{
return;
}

var foreground = appearance.ForegroundColor;
var background = appearance.BackgroundColor;
var titleColor = appearance.TitleColor;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
using Paint = Android.Graphics.Paint;
using R = Android.Resource;

#pragma warning disable IDE0031 // Use null propagation
namespace Microsoft.Maui.Controls.Platform.Compatibility
{
public class ShellToolbarTracker : Java.Lang.Object, AView.IOnClickListener, IShellToolbarTracker, IFlyoutBehaviorObserver
Expand Down Expand Up @@ -102,7 +103,10 @@ public bool CanNavigateBack
{
get
{
if (_page?.Navigation?.NavigationStack?.Count > 1)
var navStackCount = _page?.Navigation?.NavigationStack?.Count ?? 0;
var canNavFromStack = navStackCount > 1;

if (canNavFromStack)
return true;

return _canNavigateBack;
Expand Down Expand Up @@ -491,7 +495,9 @@ protected virtual async void UpdateLeftBarButtonItem(Context context, AToolbar t
defaultDrawerArrowDrawable = true;
}

icon?.Progress = (CanNavigateBack && backButtonVisible) ? 1 : 0;
var canNav = CanNavigateBack && backButtonVisible;
var progress = canNav ? 1 : 0;
icon?.Progress = progress;

if (command != null || (CanNavigateBack && backButtonVisible))
{
Expand Down Expand Up @@ -521,6 +527,11 @@ protected virtual async void UpdateLeftBarButtonItem(Context context, AToolbar t

_drawerToggle.SyncState();

// Re-apply icon Progress AFTER SyncState since SyncState resets it to 0
if (icon is not null)
{
icon.Progress = progress;
}

//this needs to be set after SyncState
UpdateToolbarIconAccessibilityText(toolbar, _shell);
Expand Down Expand Up @@ -684,6 +695,18 @@ protected virtual void UpdateToolbarItems(AToolbar toolbar, Page page)
if (SearchHandler is not null && SearchHandler.SearchBoxVisibility != SearchBoxVisibility.Hidden)
{
var context = ShellContext.AndroidContext;

// If the SearchHandler changed (e.g., navigating between pages with different SearchHandlers),
// dispose the old search view so it gets recreated with the new handler's icons/settings.
if (_searchView is not null && _searchView.SearchHandler != SearchHandler)
{
_searchView.View.RemoveFromParent();
_searchView.View.ViewAttachedToWindow -= OnSearchViewAttachedToWindow;
_searchView.SearchConfirmed -= OnSearchConfirmed;
_searchView.Dispose();
_searchView = null;
}

if (_searchView is null)
{
_searchView = GetSearchView(context);
Expand Down Expand Up @@ -744,6 +767,14 @@ protected virtual void UpdateToolbarItems(AToolbar toolbar, Page page)
}
else
{

// BUG FIX: Remove the collapsible search menu item when navigating to a page without SearchHandler
// Previously, only _searchView was cleaned up, but the menu item remained visible
if (menu.FindItem(_placeholderMenuItemId) is not null)
{
menu.RemoveItem(_placeholderMenuItemId);
}

if (_searchView is not null)
{
_searchView.View.RemoveFromParent();
Expand Down
Loading
Loading