diff --git a/src/Core/src/Platform/Android/MauiAppCompatActivity.Lifecycle.cs b/src/Core/src/Platform/Android/MauiAppCompatActivity.Lifecycle.cs index 584a692ee186..7c0280da8a86 100644 --- a/src/Core/src/Platform/Android/MauiAppCompatActivity.Lifecycle.cs +++ b/src/Core/src/Platform/Android/MauiAppCompatActivity.Lifecycle.cs @@ -27,18 +27,7 @@ protected override void OnActivityResult(int requestCode, Result resultCode, Int public override void OnBackPressed() #pragma warning restore 809 { - var preventBackPropagation = false; - IPlatformApplication.Current?.Services?.InvokeLifecycleEvents(del => - { - preventBackPropagation = del(this) || preventBackPropagation; - }); - - if (!preventBackPropagation) -#pragma warning disable CA1416 // Validate platform compatibility -#pragma warning disable CA1422 // Validate platform compatibility - base.OnBackPressed(); -#pragma warning restore CA1422 // Validate platform compatibility -#pragma warning restore CA1416 // Validate platform compatibility + HandleBackNavigation(); } public override void OnConfigurationChanged(Configuration newConfig) @@ -145,5 +134,21 @@ public override bool OnKeyUp(Keycode keyCode, KeyEvent? e) return handled || base.OnKeyUp(keyCode, e); } + + /// + /// Central handler used by both legacy and the Android 13+ predictive back gesture callback. + /// Implements lifecycle event invocation and default back stack propagation unless explicitly prevented. + /// + void HandleBackNavigation() + { + var preventBackPropagation = false; + IPlatformApplication.Current?.Services?.InvokeLifecycleEvents(del => + { + preventBackPropagation = del(this) || preventBackPropagation; + }); + + if (!preventBackPropagation) + base.OnBackPressed(); + } } } \ No newline at end of file diff --git a/src/Core/src/Platform/Android/MauiAppCompatActivity.cs b/src/Core/src/Platform/Android/MauiAppCompatActivity.cs index 839daa8cd0d5..beac14cbc615 100644 --- a/src/Core/src/Platform/Android/MauiAppCompatActivity.cs +++ b/src/Core/src/Platform/Android/MauiAppCompatActivity.cs @@ -1,5 +1,7 @@ +using System; using Android.OS; using Android.Views; +using Android.Window; using AndroidX.Activity; using AndroidX.AppCompat.App; using AndroidX.Core.Content.Resources; @@ -30,10 +32,28 @@ protected override void OnCreate(Bundle? savedInstanceState) { this.CreatePlatformWindow(IPlatformApplication.Current.Application, savedInstanceState); } + + // Register predictive back callback (Android 13+/API 33+) if available. + // This integrates MAUI lifecycle OnBackPressed events with the system back gesture animation. + // Guidance: route custom back handling through AndroidX OnBackPressedDispatcher so + // predictive back works correctly: + // https://developer.android.com/guide/navigation/custom-back/predictive-back-gesture#update-custom + if (OperatingSystem.IsAndroidVersionAtLeast(33) && _predictiveBackCallback is null) + { + _predictiveBackCallback = new PredictiveBackCallback(this); + // Priority 0 = PRIORITY_DEFAULT: callback invoked only when no higher-priority callback handles the event + OnBackInvokedDispatcher?.RegisterOnBackInvokedCallback(0, _predictiveBackCallback); + } } protected override void OnDestroy() { + if (OperatingSystem.IsAndroidVersionAtLeast(33) && _predictiveBackCallback is not null) + { + OnBackInvokedDispatcher?.UnregisterOnBackInvokedCallback(_predictiveBackCallback); + _predictiveBackCallback.Dispose(); + _predictiveBackCallback = null; + } base.OnDestroy(); } @@ -52,5 +72,22 @@ public override bool DispatchTouchEvent(MotionEvent? e) return handled || implHandled; } + + PredictiveBackCallback? _predictiveBackCallback; + + sealed class PredictiveBackCallback : Java.Lang.Object, IOnBackInvokedCallback + { + readonly MauiAppCompatActivity _activity; + public PredictiveBackCallback(MauiAppCompatActivity activity) + { + _activity = activity; + } + + public void OnBackInvoked() + { + // Reuse unified handling (will invoke lifecycle events and conditionally propagate). + _activity.HandleBackNavigation(); + } + } } } \ No newline at end of file