-
Notifications
You must be signed in to change notification settings - Fork 1.9k
predictive back gesture support for Android 13+ #32461
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Introduces a unified HandleBackNavigation method to centralize back navigation handling and integrates Android 13+ predictive back gesture callbacks with MAUI lifecycle events. Predictive back is registered and unregistered appropriately, ensuring custom back handling works with system back gesture animation.
|
Hey there @@kubaflo! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed. |
There was a problem hiding this 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 adds support for Android 13+ predictive back gesture animation by integrating with the OnBackInvokedCallback API. The implementation refactors the existing back navigation handling into a central method that can be called from both the legacy OnBackPressed override and the new predictive back callback.
Key Changes:
- Introduced
HandleBackNavigation()method to centralize back navigation logic - Registered predictive back callback in
OnCreatefor Android 13+ devices - Added cleanup logic in
OnDestroyto unregister the callback
Reviewed Changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| src/Core/src/Platform/Android/MauiAppCompatActivity.cs | Added Android.Window using directive, implemented predictive back callback registration/cleanup in OnCreate/OnDestroy, and created PredictiveBackCallback nested class |
| src/Core/src/Platform/Android/MauiAppCompatActivity.Lifecycle.cs | Refactored OnBackPressed to call new HandleBackNavigation method, which centralizes lifecycle event invocation and back propagation logic |
mattleibow
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thorough Review: Predictive Back Gesture Support for Android 13+
Summary
This PR adds predictive back gesture support for Android 13+ (API 33+) by implementing the OnBackInvokedCallback API. It centralizes back navigation handling in a new HandleBackNavigation() method used by both the legacy OnBackPressed() and the new predictive back callback system.
The approach correctly integrates MAUI's lifecycle event system with Android's predictive back gestures while maintaining backward compatibility.
Critical Issues
🔴 BLOCKING: Potential Double Registration of Callback
Location: MauiAppCompatActivity.cs, lines 44-45
The code could register the same callback multiple times if OnCreate() is called repeatedly during the activity lifecycle (e.g., configuration changes, activity recreation).
Current Code:
_predictiveBackCallback ??= new PredictiveBackCallback(this);
dispatcher?.RegisterOnBackInvokedCallback(0, _predictiveBackCallback);Issue: ??= prevents creating a new instance, but RegisterOnBackInvokedCallback() is called unconditionally, potentially registering the same callback multiple times.
Required Fix:
if (_predictiveBackCallback is null)
{
_predictiveBackCallback = new PredictiveBackCallback(this);
dispatcher?.RegisterOnBackInvokedCallback(0, _predictiveBackCallback);
}⚠️ HIGH: Missing Dispose Call
Location: MauiAppCompatActivity.cs, OnDestroy() around line 53
PredictiveBackCallback inherits from Java.Lang.Object and should be explicitly disposed to prevent memory leaks.
Current Code:
OnBackInvokedDispatcher?.UnregisterOnBackInvokedCallback(_predictiveBackCallback);
_predictiveBackCallback = null;Required Fix:
OnBackInvokedDispatcher?.UnregisterOnBackInvokedCallback(_predictiveBackCallback);
_predictiveBackCallback.Dispose();
_predictiveBackCallback = null;Design Discussion
Regarding @mattleibow's Question: Should base.OnBackPressed() be called from PredictiveBackCallback?
Answer: Yes, this is the correct approach.
Reasoning:
- MAUI Architecture: MAUI uses
AndroidLifecycle.OnBackPressedevents to allow application code to intercept and customize back navigation behavior - Platform Behavior:
base.OnBackPressed()inAppCompatActivityhandles critical platform operations:- Fragment back stack management
- Activity finishing
- Integration with AndroidX navigation components
- Compatibility: This design maintains existing MAUI navigation patterns while adding predictive back animation support
- Control Flow:
- User performs back gesture →
OnBackInvoked()called HandleBackNavigation()invokes MAUI lifecycle events- App code can set
preventBackPropagation = trueto handle custom back behavior - If not prevented →
base.OnBackPressed()performs default platform navigation
- User performs back gesture →
This unified approach correctly bridges MAUI's lifecycle system with Android's predictive back gesture API while preserving backward compatibility with Android 12 and earlier.
Minor Issues
ℹ️ LOW: Hardcoded Priority Value
Location: MauiAppCompatActivity.cs, line 45
The priority 0 is hardcoded. While correct (PRIORITY_DEFAULT = 0), adding a comment would improve clarity:
// Priority 0 = PRIORITY_DEFAULT: callback invoked only when no higher-priority callback handles the event
dispatcher?.RegisterOnBackInvokedCallback(0, _predictiveBackCallback);📝 NOTE: Pragma Warnings
The pragma warnings (CA1416/CA1422) were removed from OnBackPressed() when the code moved to HandleBackNavigation(). These warnings suppress obsolete API alerts. While the warnings aren't critical and were part of older Android code patterns, they could be re-added to HandleBackNavigation() if compiler warnings appear.
Positive Aspects ✅
- Correct API detection:
OperatingSystem.IsAndroidVersionAtLeast(33) - Proper lifecycle management: Register in
OnCreate, unregister inOnDestroy - Excellent documentation: Clear comments with Android documentation links
- Code consolidation: Unified handling reduces duplication
- Backward compatibility: Maintains support for Android 12 and earlier
Testing Requirements
Given this is a late-stage fix with potentially limited testing, thorough validation is essential:
Platform Coverage
- ✅ Android 12 and earlier: Legacy
OnBackPressed()path - ✅ Android 13+: New predictive back gesture with animation
Lifecycle Scenarios
- ✅ Configuration changes (rotation, theme changes)
- ✅ Activity recreation (low memory, background/foreground)
- ✅ Memory leak verification (repeated lifecycle events)
Navigation Scenarios
- ✅ Simple navigation (NavigationPage push/pop)
- ✅ Shell navigation
- ✅ Modal navigation
- ✅ Fragment back stack management
- ✅ Custom back handling via lifecycle events (
preventBackPropagation)
Edge Cases
- ✅ Rapid back gestures
- ✅ Interrupted/cancelled back gestures
- ✅ Back gesture while navigation in progress
Recommendation
Please address the two issues above (double registration and missing dispose) before merging. These are important for stability and proper resource management.
The overall design is sound and correctly implements predictive back gesture support while maintaining MAUI's existing navigation architecture.
This comment was marked as outdated.
This comment was marked as outdated.
- Fix potential double registration by checking if callback is null before creating/registering - Add Dispose() call in OnDestroy() to prevent memory leaks - Change field type to concrete PredictiveBackCallback for better performance (CA1859) - Add comment explaining PRIORITY_DEFAULT value These changes address code review feedback while maintaining the PR's core functionality.
Applied Code Review Fixes + Comprehensive TestingI've pushed fixes to address code review feedback and conducted extensive testing across multiple Android versions to validate both code paths. Fixes Applied1. ✅ Fixed Potential Double Registration IssueProblem: The callback could be registered multiple times if Fix: Changed from if (_predictiveBackCallback is null)
{
_predictiveBackCallback = new PredictiveBackCallback(this);
dispatcher?.RegisterOnBackInvokedCallback(0, _predictiveBackCallback);
}2. ✅ Added Missing Dispose() CallProblem: Fix: Added OnBackInvokedDispatcher?.UnregisterOnBackInvokedCallback(_predictiveBackCallback);
_predictiveBackCallback.Dispose();
_predictiveBackCallback = null;3. ✅ Fixed CA1859 Analyzer WarningProblem: Field type was Fix: Changed field type to concrete type: PredictiveBackCallback? _predictiveBackCallback;4. ✅ Added Documentation for Priority ValueAdded comment explaining the priority value Comprehensive Testing ResultsTest 1: Android API 36 (Android 14) - Modern Predictive Back PathEnvironment: Android API 36 Emulator Test Scenario: NavigationPage with push/pop navigation using system back button Results: ✅ PASS: Back navigation works correctly. App returns to first page instead of closing. Additional Testing:
Test 2: Android API 28 (Android 9) - Legacy PathEnvironment: Android API 28 Emulator Test Scenario: Same NavigationPage scenario to validate backward compatibility Initial Back Navigation Test: ✅ PASS: Back navigation works correctly on legacy Android versions. Multiple Navigation Cycles Test (4 complete cycles): Cycle 1: Cycle 2: Cycle 3: Cycle 4: ✅ PASS: All 4 cycles completed successfully without crashes or unexpected app termination. App Stability Verification: $ adb shell "ps -A | grep sandbox"
u0_a95 9617 1468 3781072 236732 0 0 S com.microsoft.maui.sandbox✅ PASS: App remains stable and running after extensive testing. Summary✅ Both Code Paths ValidatedModern Path (API 33+):
Legacy Path (API < 33):
Key Findings
The PR is now ready for final review and merge. |
|
/azp run MAUI-UITests-public |
|
Azure Pipelines successfully started running 1 pipeline(s). |
|
Thanks @mattleibow! & @copilot |
* Add predictive back gesture support for Android 13+ Introduces a unified HandleBackNavigation method to centralize back navigation handling and integrates Android 13+ predictive back gesture callbacks with MAUI lifecycle events. Predictive back is registered and unregistered appropriately, ensuring custom back handling works with system back gesture animation. * Fix predictive back callback registration and resource management - Fix potential double registration by checking if callback is null before creating/registering - Add Dispose() call in OnDestroy() to prevent memory leaks - Change field type to concrete PredictiveBackCallback for better performance (CA1859) - Add comment explaining PRIORITY_DEFAULT value These changes address code review feedback while maintaining the PR's core functionality. * Simplify code to reduce nesting --------- Co-authored-by: Matthew Leibowitz <[email protected]>
* Add predictive back gesture support for Android 13+ Introduces a unified HandleBackNavigation method to centralize back navigation handling and integrates Android 13+ predictive back gesture callbacks with MAUI lifecycle events. Predictive back is registered and unregistered appropriately, ensuring custom back handling works with system back gesture animation. * Fix predictive back callback registration and resource management - Fix potential double registration by checking if callback is null before creating/registering - Add Dispose() call in OnDestroy() to prevent memory leaks - Change field type to concrete PredictiveBackCallback for better performance (CA1859) - Add comment explaining PRIORITY_DEFAULT value These changes address code review feedback while maintaining the PR's core functionality. * Simplify code to reduce nesting --------- Co-authored-by: Matthew Leibowitz <[email protected]>
|
/backport to release/10.0.1xx-sr1 |
|
Started backporting to |
* Add predictive back gesture support for Android 13+ Introduces a unified HandleBackNavigation method to centralize back navigation handling and integrates Android 13+ predictive back gesture callbacks with MAUI lifecycle events. Predictive back is registered and unregistered appropriately, ensuring custom back handling works with system back gesture animation. * Fix predictive back callback registration and resource management - Fix potential double registration by checking if callback is null before creating/registering - Add Dispose() call in OnDestroy() to prevent memory leaks - Change field type to concrete PredictiveBackCallback for better performance (CA1859) - Add comment explaining PRIORITY_DEFAULT value These changes address code review feedback while maintaining the PR's core functionality. * Simplify code to reduce nesting --------- Co-authored-by: Matthew Leibowitz <[email protected]>
* Add predictive back gesture support for Android 13+ Introduces a unified HandleBackNavigation method to centralize back navigation handling and integrates Android 13+ predictive back gesture callbacks with MAUI lifecycle events. Predictive back is registered and unregistered appropriately, ensuring custom back handling works with system back gesture animation. * Fix predictive back callback registration and resource management - Fix potential double registration by checking if callback is null before creating/registering - Add Dispose() call in OnDestroy() to prevent memory leaks - Change field type to concrete PredictiveBackCallback for better performance (CA1859) - Add comment explaining PRIORITY_DEFAULT value These changes address code review feedback while maintaining the PR's core functionality. * Simplify code to reduce nesting --------- Co-authored-by: Matthew Leibowitz <[email protected]>
* Add predictive back gesture support for Android 13+ Introduces a unified HandleBackNavigation method to centralize back navigation handling and integrates Android 13+ predictive back gesture callbacks with MAUI lifecycle events. Predictive back is registered and unregistered appropriately, ensuring custom back handling works with system back gesture animation. * Fix predictive back callback registration and resource management - Fix potential double registration by checking if callback is null before creating/registering - Add Dispose() call in OnDestroy() to prevent memory leaks - Change field type to concrete PredictiveBackCallback for better performance (CA1859) - Add comment explaining PRIORITY_DEFAULT value These changes address code review feedback while maintaining the PR's core functionality. * Simplify code to reduce nesting --------- Co-authored-by: Matthew Leibowitz <[email protected]>
* Add predictive back gesture support for Android 13+ Introduces a unified HandleBackNavigation method to centralize back navigation handling and integrates Android 13+ predictive back gesture callbacks with MAUI lifecycle events. Predictive back is registered and unregistered appropriately, ensuring custom back handling works with system back gesture animation. * Fix predictive back callback registration and resource management - Fix potential double registration by checking if callback is null before creating/registering - Add Dispose() call in OnDestroy() to prevent memory leaks - Change field type to concrete PredictiveBackCallback for better performance (CA1859) - Add comment explaining PRIORITY_DEFAULT value These changes address code review feedback while maintaining the PR's core functionality. * Simplify code to reduce nesting --------- Co-authored-by: Matthew Leibowitz <[email protected]>
* Add predictive back gesture support for Android 13+ Introduces a unified HandleBackNavigation method to centralize back navigation handling and integrates Android 13+ predictive back gesture callbacks with MAUI lifecycle events. Predictive back is registered and unregistered appropriately, ensuring custom back handling works with system back gesture animation. * Fix predictive back callback registration and resource management - Fix potential double registration by checking if callback is null before creating/registering - Add Dispose() call in OnDestroy() to prevent memory leaks - Change field type to concrete PredictiveBackCallback for better performance (CA1859) - Add comment explaining PRIORITY_DEFAULT value These changes address code review feedback while maintaining the PR's core functionality. * Simplify code to reduce nesting --------- Co-authored-by: Matthew Leibowitz <[email protected]>
* Add predictive back gesture support for Android 13+ Introduces a unified HandleBackNavigation method to centralize back navigation handling and integrates Android 13+ predictive back gesture callbacks with MAUI lifecycle events. Predictive back is registered and unregistered appropriately, ensuring custom back handling works with system back gesture animation. * Fix predictive back callback registration and resource management - Fix potential double registration by checking if callback is null before creating/registering - Add Dispose() call in OnDestroy() to prevent memory leaks - Change field type to concrete PredictiveBackCallback for better performance (CA1859) - Add comment explaining PRIORITY_DEFAULT value These changes address code review feedback while maintaining the PR's core functionality. * Simplify code to reduce nesting --------- Co-authored-by: Matthew Leibowitz <[email protected]>
* Add predictive back gesture support for Android 13+ Introduces a unified HandleBackNavigation method to centralize back navigation handling and integrates Android 13+ predictive back gesture callbacks with MAUI lifecycle events. Predictive back is registered and unregistered appropriately, ensuring custom back handling works with system back gesture animation. * Fix predictive back callback registration and resource management - Fix potential double registration by checking if callback is null before creating/registering - Add Dispose() call in OnDestroy() to prevent memory leaks - Change field type to concrete PredictiveBackCallback for better performance (CA1859) - Add comment explaining PRIORITY_DEFAULT value These changes address code review feedback while maintaining the PR's core functionality. * Simplify code to reduce nesting --------- Co-authored-by: Matthew Leibowitz <[email protected]>
This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [Microsoft.Maui.Controls](https://github.com/dotnet/maui) | nuget | patch | `10.0.10` -> `10.0.11` | --- ### Release Notes <details> <summary>dotnet/maui (Microsoft.Maui.Controls)</summary> ### [`v10.0.11`](https://github.com/dotnet/maui/releases/tag/10.0.11): SR1.1 [Compare Source](dotnet/maui@10.0.10...10.0.11) ##### What's Changed .NET MAUI 10.0.11 introduces significant improvements across all platforms with focus on quality, performance, and developer experience. This release includes 11 commits with various improvements, bug fixes, and enhancements. ##### .NET MAUI Product Fixes ##### Android - Fix content page title clipping on Android API < 30 with window insets compatibility by [@​Copilot](https://github.com/Copilot) in dotnet/maui#32738 <details> <summary>🔧 Fixes</summary> - [Shell content page title position incorrect/clipped](dotnet/maui#32526) </details> ##### Button - \[release/10.0.1xx-sr1] Removed Value property coercion in RadioButton by [@​github-actions](https://github.com/github-actions)\[bot] in dotnet/maui#32604 <details> <summary>🔧 Fixes</summary> - [Removed Value property coercion in RadioButton](dotnet/maui#32489) </details> ##### DateTimePicker - Fix crash when TimePicker.Time is set to null (backport from PR [#​32660](dotnet/maui#32660)) by [@​Copilot](https://github.com/Copilot) in dotnet/maui#32715 <details> <summary>🔧 Fixes</summary> - [Fix crash when TimePicker.Time is set to null](dotnet/maui#32660) </details> ##### Gestures - \[release/10.0.1xx-sr1] predictive back gesture support for Android 13+ by [@​github-actions](https://github.com/github-actions)\[bot] in dotnet/maui#32635 <details> <summary>🔧 Fixes</summary> - [predictive back gesture support for Android 13+](dotnet/maui#32461) </details> ##### Infrastructure - \[release/10.0.1xx-sr1] \[ci] Revert changes setting Creator by [@​github-actions](https://github.com/github-actions)\[bot] in dotnet/maui#32803 <details> <summary>🔧 Fixes</summary> - [\[ci\] Revert changes setting Creator](dotnet/maui#32743) </details> ##### Mediapicker - \[release/10.0.1xx-sr1] \[Android] Refactor selection limit handling in MediaPicker by [@​github-actions](https://github.com/github-actions)\[bot] in dotnet/maui#32628 <details> <summary>🔧 Fixes</summary> - [\[Android\] Refactor selection limit handling in MediaPicker](dotnet/maui#32571) ...
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 PR introduces a unified HandleBackNavigation method to centralize and standardize back navigation logic across platforms.
On Android 13 (API 33) and above, it integrates predictive back gesture callbacks with the MAUI lifecycle, ensuring that custom back navigation seamlessly participates in the system’s predictive back animations.
For more information on predictive back navigation, see the official Android documentation:
https://developer.android.com/guide/navigation/custom-back/predictive-back-gesture#update-custom
Issues Fixed
Fixes #32458
Fixes #32750