From 6722e3d5166d84acffd80dc7173300681f1912d5 Mon Sep 17 00:00:00 2001 From: Adam Barth Date: Sat, 20 Feb 2016 22:06:00 -0800 Subject: [PATCH] Animation status callbacks should be re-entrant We should mutate the status of the AnimationController before calling the status callbacks so that we're prepared to be re-entered. Fixes #1911 --- .../src/animation/animation_controller.dart | 9 +++-- .../animation/animation_controller_test.dart | 40 +++++++++++++++++++ 2 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 packages/flutter/test/animation/animation_controller_test.dart diff --git a/packages/flutter/lib/src/animation/animation_controller.dart b/packages/flutter/lib/src/animation/animation_controller.dart index 124aa31285..b6846a9aa6 100644 --- a/packages/flutter/lib/src/animation/animation_controller.dart +++ b/packages/flutter/lib/src/animation/animation_controller.dart @@ -163,10 +163,11 @@ class AnimationController extends Animation AnimationStatus _lastStatus = AnimationStatus.dismissed; void _checkStatusChanged() { - AnimationStatus currentStatus = status; - if (currentStatus != _lastStatus) - notifyStatusListeners(status); - _lastStatus = currentStatus; + AnimationStatus newStatus = status; + AnimationStatus oldStatus = _lastStatus; + _lastStatus = newStatus; + if (oldStatus != newStatus) + notifyStatusListeners(newStatus); } /// Drives the animation from its current value to target. diff --git a/packages/flutter/test/animation/animation_controller_test.dart b/packages/flutter/test/animation/animation_controller_test.dart new file mode 100644 index 0000000000..cb283f5612 --- /dev/null +++ b/packages/flutter/test/animation/animation_controller_test.dart @@ -0,0 +1,40 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/animation.dart'; +import 'package:flutter/scheduler.dart'; +import 'package:flutter/widgets.dart'; +import 'package:test/test.dart'; + +void main() { + test("Can set value during status callback", () { + WidgetFlutterBinding.ensureInitialized(); + AnimationController controller = new AnimationController( + duration: const Duration(milliseconds: 100) + ); + bool didComplete = false; + bool didDismiss = false; + controller.addStatusListener((AnimationStatus status) { + if (status == AnimationStatus.completed) { + didComplete = true; + controller.value = 0.0; + controller.forward(); + } else if (status == AnimationStatus.dismissed) { + didDismiss = true; + controller.value = 0.0; + controller.forward(); + } + }); + + controller.forward(); + expect(didComplete, isFalse); + expect(didDismiss, isFalse); + Scheduler.instance.handleBeginFrame(const Duration(seconds: 1)); + expect(didComplete, isFalse); + expect(didDismiss, isFalse); + Scheduler.instance.handleBeginFrame(const Duration(seconds: 2)); + expect(didComplete, isTrue); + expect(didDismiss, isTrue); + }); +}