From 8e2da8414c26ab0dcba90b543d34b5d5b47ad5c8 Mon Sep 17 00:00:00 2001 From: maRci002 Date: Wed, 7 Feb 2024 19:01:22 +0100 Subject: [PATCH] Handle transitions to AppLifecycleState.detached in lifecycle state generation (#142523) Generates the correct lifecycle state transitions in ServicesBinding when detaching. --- packages/flutter/lib/src/services/binding.dart | 13 ++++++------- .../test/widgets/app_lifecycle_listener_test.dart | 11 +++++++---- packages/flutter/test/widgets/binding_test.dart | 8 +++++++- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/packages/flutter/lib/src/services/binding.dart b/packages/flutter/lib/src/services/binding.dart index 60ee9572cd0..2659e43e167 100644 --- a/packages/flutter/lib/src/services/binding.dart +++ b/packages/flutter/lib/src/services/binding.dart @@ -289,12 +289,6 @@ mixin ServicesBinding on BindingBase, SchedulerBinding { if (previousState == state) { return const []; } - if (previousState == AppLifecycleState.paused && state == AppLifecycleState.detached) { - // Handle the wrap-around from paused to detached - return const [ - AppLifecycleState.detached, - ]; - } final List stateChanges = []; if (previousState == null) { // If there was no previous state, just jump directly to the new state. @@ -304,7 +298,12 @@ mixin ServicesBinding on BindingBase, SchedulerBinding { final int stateIndex = AppLifecycleState.values.indexOf(state); assert(previousStateIndex != -1, 'State $previousState missing in stateOrder array'); assert(stateIndex != -1, 'State $state missing in stateOrder array'); - if (previousStateIndex > stateIndex) { + if (state == AppLifecycleState.detached) { + for (int i = previousStateIndex + 1; i < AppLifecycleState.values.length; ++i) { + stateChanges.add(AppLifecycleState.values[i]); + } + stateChanges.add(AppLifecycleState.detached); + } else if (previousStateIndex > stateIndex) { for (int i = stateIndex; i < previousStateIndex; ++i) { stateChanges.insert(0, AppLifecycleState.values[i]); } diff --git a/packages/flutter/test/widgets/app_lifecycle_listener_test.dart b/packages/flutter/test/widgets/app_lifecycle_listener_test.dart index 9e0ec667952..50012593523 100644 --- a/packages/flutter/test/widgets/app_lifecycle_listener_test.dart +++ b/packages/flutter/test/widgets/app_lifecycle_listener_test.dart @@ -129,10 +129,11 @@ void main() { await setAppLifeCycleState(AppLifecycleState.resumed); expect(transitions, equals(['restart', 'show', 'resume'])); - // Generates intermediate states. + // Generates intermediate states from lower to higher lifecycle states. transitions.clear(); await setAppLifeCycleState(AppLifecycleState.paused); expect(transitions, equals(['inactive', 'hide', 'pause'])); + // Wraps around from pause to detach. await setAppLifeCycleState(AppLifecycleState.detached); expect(transitions, equals(['inactive', 'hide', 'pause', 'detach'])); @@ -140,14 +141,16 @@ void main() { expect(transitions, equals(['inactive', 'hide', 'pause', 'detach', 'resume'])); await setAppLifeCycleState(AppLifecycleState.paused); expect(transitions, equals(['inactive', 'hide', 'pause', 'detach', 'resume', 'inactive', 'hide', 'pause'])); + + // Generates intermediate states from higher to lower lifecycle states. transitions.clear(); await setAppLifeCycleState(AppLifecycleState.resumed); expect(transitions, equals(['restart', 'show', 'resume'])); - // Asserts on bad transitions - await expectLater(() => setAppLifeCycleState(AppLifecycleState.detached), throwsAssertionError); - await setAppLifeCycleState(AppLifecycleState.paused); + // Go to detached + transitions.clear(); await setAppLifeCycleState(AppLifecycleState.detached); + expect(transitions, equals(['inactive', 'hide', 'pause', 'detach'])); }); testWidgets('Receives exit requests', (WidgetTester tester) async { diff --git a/packages/flutter/test/widgets/binding_test.dart b/packages/flutter/test/widgets/binding_test.dart index d7f71478611..a591474bf1c 100644 --- a/packages/flutter/test/widgets/binding_test.dart +++ b/packages/flutter/test/widgets/binding_test.dart @@ -224,7 +224,13 @@ void main() { ]); observer.accumulatedStates.clear(); - await expectLater(() async => setAppLifeCycleState(AppLifecycleState.detached), throwsAssertionError); + await setAppLifeCycleState(AppLifecycleState.detached); + expect(observer.accumulatedStates, [ + AppLifecycleState.inactive, + AppLifecycleState.hidden, + AppLifecycleState.paused, + AppLifecycleState.detached, + ]); WidgetsBinding.instance.removeObserver(observer); });