diff --git a/packages/flutter/lib/src/widgets/binding.dart b/packages/flutter/lib/src/widgets/binding.dart index b30b3d18844..d0d9382515d 100644 --- a/packages/flutter/lib/src/widgets/binding.dart +++ b/packages/flutter/lib/src/widgets/binding.dart @@ -830,13 +830,14 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB /// {@endtemplate} @protected @visibleForTesting - Future handlePopRoute() async { + Future handlePopRoute() async { for (final WidgetsBindingObserver observer in List.of(_observers)) { if (await observer.didPopRoute()) { - return; + return true; } } SystemNavigator.pop(); + return false; } // The observer that is currently handling an active predictive back gesture. @@ -870,7 +871,8 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB // back gesture occurs but no predictive back route transition exists to // handle it. The back gesture should still cause normal pop even if it // doesn't cause a predictive transition. - return handlePopRoute(); + await handlePopRoute(); + return; } _backGestureObserver?.handleCommitBackGesture(); } @@ -896,33 +898,36 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB @protected @mustCallSuper @visibleForTesting - Future handlePushRoute(String route) async { + Future handlePushRoute(String route) async { final RouteInformation routeInformation = RouteInformation(uri: Uri.parse(route)); for (final WidgetsBindingObserver observer in List.of(_observers)) { if (await observer.didPushRouteInformation(routeInformation)) { - return; + return true; } } + return false; } - Future _handlePushRouteInformation(Map routeArguments) async { + Future _handlePushRouteInformation(Map routeArguments) async { final RouteInformation routeInformation = RouteInformation( uri: Uri.parse(routeArguments['location'] as String), state: routeArguments['state'] as Object?, ); for (final WidgetsBindingObserver observer in List.of(_observers)) { if (await observer.didPushRouteInformation(routeInformation)) { - return; + return true; } } + return false; } - Future _handleNavigationInvocation(MethodCall methodCall) { + Future _handleNavigationInvocation(MethodCall methodCall) { return switch (methodCall.method) { 'popRoute' => handlePopRoute(), 'pushRoute' => handlePushRoute(methodCall.arguments as String), 'pushRouteInformation' => _handlePushRouteInformation(methodCall.arguments as Map), - _ => Future.value(), + // Return false for unhandled method. + _ => Future.value(false), }; } diff --git a/packages/flutter/test/widgets/binding_test.dart b/packages/flutter/test/widgets/binding_test.dart index 315291315ad..b85553cc377 100644 --- a/packages/flutter/test/widgets/binding_test.dart +++ b/packages/flutter/test/widgets/binding_test.dart @@ -268,7 +268,11 @@ void main() { const String testRouteName = 'testRouteName'; final ByteData message = const JSONMethodCodec().encodeMethodCall(const MethodCall('pushRoute', testRouteName)); - await tester.binding.defaultBinaryMessenger.handlePlatformMessage('flutter/navigation', message, (_) {}); + final ByteData result = (await tester.binding.defaultBinaryMessenger + .handlePlatformMessage('flutter/navigation', message, (_) {}))!; + final bool decodedResult = const JSONMethodCodec().decodeEnvelope(result) as bool; + + expect(decodedResult, true); expect(observer.pushedRoute, testRouteName); WidgetsBinding.instance.removeObserver(observer); @@ -286,8 +290,11 @@ void main() { final ByteData message = const JSONMethodCodec().encodeMethodCall( const MethodCall('pushRouteInformation', testRouteInformation), ); - await tester.binding.defaultBinaryMessenger - .handlePlatformMessage('flutter/navigation', message, (_) {}); + final ByteData result = (await tester.binding.defaultBinaryMessenger + .handlePlatformMessage('flutter/navigation', message, (_) {}))!; + final bool decodedResult = const JSONMethodCodec().decodeEnvelope(result) as bool; + + expect(decodedResult, true); expect(observer.pushedRoute, 'testRouteName'); WidgetsBinding.instance.removeObserver(observer); }); @@ -377,6 +384,49 @@ void main() { WidgetsBinding.instance.removeObserver(observer); }); + testWidgets('pushRouteInformation not handled by observer returns false', (WidgetTester tester) async { + + const Map testRouteInformation = { + 'location': 'testRouteName', + 'state': null, + }; + final ByteData message = const JSONMethodCodec().encodeMethodCall( + const MethodCall('pushRouteInformation', testRouteInformation), + ); + + final ByteData result = (await tester.binding.defaultBinaryMessenger + .handlePlatformMessage('flutter/navigation', message, (_) {}))!; + final bool decodedResult = const JSONMethodCodec().decodeEnvelope(result) as bool; + + expect(decodedResult, false); + }); + + testWidgets('pushRoute not handled by observer returns false', (WidgetTester tester) async { + + const String testRoute = 'testRouteName'; + final ByteData message = const JSONMethodCodec().encodeMethodCall( + const MethodCall('pushRoute', testRoute), + ); + + final ByteData result = (await tester.binding.defaultBinaryMessenger + .handlePlatformMessage('flutter/navigation', message, (_) {}))!; + final bool decodedResult = const JSONMethodCodec().decodeEnvelope(result) as bool; + + expect(decodedResult, false); + }); + + + testWidgets('popRoute not handled by observer returns false', (WidgetTester tester) async { + final ByteData message = const JSONMethodCodec().encodeMethodCall( + const MethodCall('popRoute'), + ); + + final ByteData result = (await tester.binding.defaultBinaryMessenger + .handlePlatformMessage('flutter/navigation', message, (_) {}))!; + final bool decodedResult = const JSONMethodCodec().decodeEnvelope(result) as bool; + + expect(decodedResult, false); + }); testWidgets('Application lifecycle affects frame scheduling', (WidgetTester tester) async { expect(tester.binding.hasScheduledFrame, isFalse);