Skip to content

Commit

Permalink
Update _handlePushRouteInformation to Future<bool> to indicate whethe…
Browse files Browse the repository at this point in the history
…r any of the observer has handled the route or not (#147901)

follow up on comments on flutter/engine#52350
  • Loading branch information
hangyujin committed May 15, 2024
1 parent 8b129b9 commit 6826fc0
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 12 deletions.
23 changes: 14 additions & 9 deletions packages/flutter/lib/src/widgets/binding.dart
Original file line number Diff line number Diff line change
Expand Up @@ -830,13 +830,14 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
/// {@endtemplate}
@protected
@visibleForTesting
Future<void> handlePopRoute() async {
Future<bool> handlePopRoute() async {
for (final WidgetsBindingObserver observer in List<WidgetsBindingObserver>.of(_observers)) {
if (await observer.didPopRoute()) {
return;
return true;
}
}
SystemNavigator.pop();
return false;
}

// The observer that is currently handling an active predictive back gesture.
Expand Down Expand Up @@ -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();
}
Expand All @@ -896,33 +898,36 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
@protected
@mustCallSuper
@visibleForTesting
Future<void> handlePushRoute(String route) async {
Future<bool> handlePushRoute(String route) async {
final RouteInformation routeInformation = RouteInformation(uri: Uri.parse(route));
for (final WidgetsBindingObserver observer in List<WidgetsBindingObserver>.of(_observers)) {
if (await observer.didPushRouteInformation(routeInformation)) {
return;
return true;
}
}
return false;
}

Future<void> _handlePushRouteInformation(Map<dynamic, dynamic> routeArguments) async {
Future<bool> _handlePushRouteInformation(Map<dynamic, dynamic> routeArguments) async {
final RouteInformation routeInformation = RouteInformation(
uri: Uri.parse(routeArguments['location'] as String),
state: routeArguments['state'] as Object?,
);
for (final WidgetsBindingObserver observer in List<WidgetsBindingObserver>.of(_observers)) {
if (await observer.didPushRouteInformation(routeInformation)) {
return;
return true;
}
}
return false;
}

Future<dynamic> _handleNavigationInvocation(MethodCall methodCall) {
Future<bool> _handleNavigationInvocation(MethodCall methodCall) {
return switch (methodCall.method) {
'popRoute' => handlePopRoute(),
'pushRoute' => handlePushRoute(methodCall.arguments as String),
'pushRouteInformation' => _handlePushRouteInformation(methodCall.arguments as Map<dynamic, dynamic>),
_ => Future<dynamic>.value(),
// Return false for unhandled method.
_ => Future<bool>.value(false),
};
}

Expand Down
56 changes: 53 additions & 3 deletions packages/flutter/test/widgets/binding_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
});
Expand Down Expand Up @@ -377,6 +384,49 @@ void main() {
WidgetsBinding.instance.removeObserver(observer);
});

testWidgets('pushRouteInformation not handled by observer returns false', (WidgetTester tester) async {

const Map<String, dynamic> testRouteInformation = <String, dynamic>{
'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);

Expand Down

0 comments on commit 6826fc0

Please sign in to comment.