Unverified Commit 908de76c authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

Remove value listener from semantics bindings (#21296)

parent 976cffa2
...@@ -14,5 +14,6 @@ ...@@ -14,5 +14,6 @@
library semantics; library semantics;
export 'src/semantics/binding.dart'; export 'src/semantics/binding.dart';
export 'src/semantics/debug.dart';
export 'src/semantics/semantics.dart'; export 'src/semantics/semantics.dart';
export 'src/semantics/semantics_service.dart'; export 'src/semantics/semantics_service.dart';
...@@ -401,7 +401,7 @@ class AnimationController extends Animation<double> ...@@ -401,7 +401,7 @@ class AnimationController extends Animation<double>
TickerFuture _animateToInternal(double target, { Duration duration, Curve curve = Curves.linear, AnimationBehavior animationBehavior }) { TickerFuture _animateToInternal(double target, { Duration duration, Curve curve = Curves.linear, AnimationBehavior animationBehavior }) {
final AnimationBehavior behavior = animationBehavior ?? this.animationBehavior; final AnimationBehavior behavior = animationBehavior ?? this.animationBehavior;
double scale = 1.0; double scale = 1.0;
if (_ticker.disableAnimations) { if (SemanticsBinding.instance.disableAnimations) {
switch (behavior) { switch (behavior) {
case AnimationBehavior.normal: case AnimationBehavior.normal:
// Since the framework cannot handle zero duration animations, we run it at 5% of the normal // Since the framework cannot handle zero duration animations, we run it at 5% of the normal
...@@ -496,7 +496,7 @@ class AnimationController extends Animation<double> ...@@ -496,7 +496,7 @@ class AnimationController extends Animation<double>
: upperBound + _kFlingTolerance.distance; : upperBound + _kFlingTolerance.distance;
double scale = 1.0; double scale = 1.0;
final AnimationBehavior behavior = animationBehavior ?? this.animationBehavior; final AnimationBehavior behavior = animationBehavior ?? this.animationBehavior;
if (_ticker.disableAnimations) { if (SemanticsBinding.instance.disableAnimations) {
switch (behavior) { switch (behavior) {
case AnimationBehavior.normal: case AnimationBehavior.normal:
// TODO(jonahwilliams): determine a better process for setting velocity. // TODO(jonahwilliams): determine a better process for setting velocity.
......
...@@ -68,12 +68,6 @@ class Ticker { ...@@ -68,12 +68,6 @@ class Ticker {
TickerFuture _future; TickerFuture _future;
/// Whether or not the platform is requesting that animations be disabled.
///
/// See also:
/// * [AccessibilityFeatures.disableAnimations], for the setting this value comes from.
bool disableAnimations = false;
/// Whether this ticker has been silenced. /// Whether this ticker has been silenced.
/// ///
/// While silenced, a ticker's clock can still run, but the callback will not /// While silenced, a ticker's clock can still run, but the callback will not
...@@ -279,7 +273,6 @@ class Ticker { ...@@ -279,7 +273,6 @@ class Ticker {
assert(_startTime == null); assert(_startTime == null);
assert(_animationId == null); assert(_animationId == null);
assert((originalTicker._future == null) == (originalTicker._startTime == null), 'Cannot absorb Ticker after it has been disposed.'); assert((originalTicker._future == null) == (originalTicker._startTime == null), 'Cannot absorb Ticker after it has been disposed.');
disableAnimations = originalTicker.disableAnimations;
if (originalTicker._future != null) { if (originalTicker._future != null) {
_future = originalTicker._future; _future = originalTicker._future;
_startTime = originalTicker._startTime; _startTime = originalTicker._startTime;
......
...@@ -6,6 +6,8 @@ import 'dart:ui' as ui show AccessibilityFeatures, window; ...@@ -6,6 +6,8 @@ import 'dart:ui' as ui show AccessibilityFeatures, window;
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'debug.dart';
export 'dart:ui' show AccessibilityFeatures; export 'dart:ui' show AccessibilityFeatures;
/// The glue between the semantics layer and the Flutter engine. /// The glue between the semantics layer and the Flutter engine.
...@@ -23,7 +25,7 @@ class SemanticsBinding extends BindingBase { ...@@ -23,7 +25,7 @@ class SemanticsBinding extends BindingBase {
void initInstances() { void initInstances() {
super.initInstances(); super.initInstances();
_instance = this; _instance = this;
_accessibilityFeatures = new ValueNotifier<ui.AccessibilityFeatures>(ui.window.accessibilityFeatures); _accessibilityFeatures = ui.window.accessibilityFeatures;
} }
/// Called when the platform accessibility features change. /// Called when the platform accessibility features change.
...@@ -31,7 +33,7 @@ class SemanticsBinding extends BindingBase { ...@@ -31,7 +33,7 @@ class SemanticsBinding extends BindingBase {
/// See [Window.onAccessibilityFeaturesChanged]. /// See [Window.onAccessibilityFeaturesChanged].
@protected @protected
void handleAccessibilityFeaturesChanged() { void handleAccessibilityFeaturesChanged() {
_accessibilityFeatures.value = ui.window.accessibilityFeatures; _accessibilityFeatures = ui.window.accessibilityFeatures;
} }
/// The currently active set of [AccessibilityFeatures]. /// The currently active set of [AccessibilityFeatures].
...@@ -41,6 +43,20 @@ class SemanticsBinding extends BindingBase { ...@@ -41,6 +43,20 @@ class SemanticsBinding extends BindingBase {
/// ///
/// To listen to changes to accessibility features, create a /// To listen to changes to accessibility features, create a
/// [WidgetsBindingObserver] and listen to [didChangeAccessibilityFeatures]. /// [WidgetsBindingObserver] and listen to [didChangeAccessibilityFeatures].
ValueListenable<ui.AccessibilityFeatures> get accessibilityFeatures => _accessibilityFeatures; ui.AccessibilityFeatures get accessibilityFeatures => _accessibilityFeatures;
ValueNotifier<ui.AccessibilityFeatures> _accessibilityFeatures; ui.AccessibilityFeatures _accessibilityFeatures;
/// The platform is requesting that animations be disabled or simplified.
///
/// This setting can be overriden for testing or debugging by setting
/// [debugSemanticsDisableAnimations].
bool get disableAnimations {
bool value = _accessibilityFeatures.disableAnimations;
assert(() {
if (debugSemanticsDisableAnimations != null)
value = debugSemanticsDisableAnimations;
return true;
}());
return value;
}
} }
// Copyright 2018 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.
/// Overrides the setting of [SemanticsBinding.disableAnimations] for debugging
/// and testing.
///
/// This value is ignored in non-debug builds.
bool debugSemanticsDisableAnimations;
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
import 'package:flutter/semantics.dart';
import 'framework.dart'; import 'framework.dart';
...@@ -95,10 +94,7 @@ abstract class SingleTickerProviderStateMixin<T extends StatefulWidget> extends ...@@ -95,10 +94,7 @@ abstract class SingleTickerProviderStateMixin<T extends StatefulWidget> extends
'mixing in a SingleTickerProviderStateMixin, use a regular TickerProviderStateMixin.' 'mixing in a SingleTickerProviderStateMixin, use a regular TickerProviderStateMixin.'
); );
}()); }());
final ValueListenable<AccessibilityFeatures> accessibilityFeatures = SemanticsBinding.instance.accessibilityFeatures; _ticker = new Ticker(onTick, debugLabel: 'created by $this');
_ticker = new Ticker(onTick, debugLabel: 'created by $this')
..disableAnimations = accessibilityFeatures.value.disableAnimations;
accessibilityFeatures.addListener(_handleAccessibilityFeaturesChanged);
// We assume that this is called from initState, build, or some sort of // We assume that this is called from initState, build, or some sort of
// event handler, and that thus TickerMode.of(context) would return true. We // event handler, and that thus TickerMode.of(context) would return true. We
// can't actually check that here because if we're in initState then we're // can't actually check that here because if we're in initState then we're
...@@ -121,8 +117,6 @@ abstract class SingleTickerProviderStateMixin<T extends StatefulWidget> extends ...@@ -121,8 +117,6 @@ abstract class SingleTickerProviderStateMixin<T extends StatefulWidget> extends
'The offending ticker was: ${_ticker.toString(debugIncludeStack: true)}' 'The offending ticker was: ${_ticker.toString(debugIncludeStack: true)}'
); );
}()); }());
final ValueListenable<AccessibilityFeatures> accessibilityFeatures = SemanticsBinding.instance.accessibilityFeatures;
accessibilityFeatures.removeListener(_handleAccessibilityFeaturesChanged);
super.dispose(); super.dispose();
} }
...@@ -149,13 +143,6 @@ abstract class SingleTickerProviderStateMixin<T extends StatefulWidget> extends ...@@ -149,13 +143,6 @@ abstract class SingleTickerProviderStateMixin<T extends StatefulWidget> extends
} }
properties.add(new DiagnosticsProperty<Ticker>('ticker', _ticker, description: tickerDescription, showSeparator: false, defaultValue: null)); properties.add(new DiagnosticsProperty<Ticker>('ticker', _ticker, description: tickerDescription, showSeparator: false, defaultValue: null));
} }
void _handleAccessibilityFeaturesChanged() {
final ValueListenable<AccessibilityFeatures> accessibilityFeatures = SemanticsBinding.instance.accessibilityFeatures;
if (_ticker != null) {
_ticker.disableAnimations = accessibilityFeatures.value.disableAnimations;
}
}
} }
/// Provides [Ticker] objects that are configured to only tick while the current /// Provides [Ticker] objects that are configured to only tick while the current
...@@ -179,11 +166,8 @@ abstract class TickerProviderStateMixin<T extends StatefulWidget> extends State< ...@@ -179,11 +166,8 @@ abstract class TickerProviderStateMixin<T extends StatefulWidget> extends State<
@override @override
Ticker createTicker(TickerCallback onTick) { Ticker createTicker(TickerCallback onTick) {
_tickers ??= new Set<_WidgetTicker>(); _tickers ??= new Set<_WidgetTicker>();
final ValueListenable<AccessibilityFeatures> accessibilityFeatures = SemanticsBinding.instance.accessibilityFeatures; final _WidgetTicker result = new _WidgetTicker(onTick, this, debugLabel: 'created by $this');
final _WidgetTicker result = new _WidgetTicker(onTick, this, debugLabel: 'created by $this')
..disableAnimations = accessibilityFeatures.value.disableAnimations;
_tickers.add(result); _tickers.add(result);
accessibilityFeatures.addListener(_handleAccessibilityFeaturesChanged);
return result; return result;
} }
...@@ -213,8 +197,6 @@ abstract class TickerProviderStateMixin<T extends StatefulWidget> extends State< ...@@ -213,8 +197,6 @@ abstract class TickerProviderStateMixin<T extends StatefulWidget> extends State<
} }
return true; return true;
}()); }());
final ValueListenable<AccessibilityFeatures> accessibilityFeatures = SemanticsBinding.instance.accessibilityFeatures;
accessibilityFeatures.removeListener(_handleAccessibilityFeaturesChanged);
super.dispose(); super.dispose();
} }
...@@ -241,15 +223,6 @@ abstract class TickerProviderStateMixin<T extends StatefulWidget> extends State< ...@@ -241,15 +223,6 @@ abstract class TickerProviderStateMixin<T extends StatefulWidget> extends State<
defaultValue: null, defaultValue: null,
)); ));
} }
void _handleAccessibilityFeaturesChanged() {
final ValueListenable<AccessibilityFeatures> accessibilityFeatures = SemanticsBinding.instance.accessibilityFeatures;
if (_tickers != null) {
for (Ticker ticker in _tickers) {
ticker.disableAnimations = accessibilityFeatures.value.disableAnimations;
}
}
}
} }
// This class should really be called _DisposingTicker or some such, but this // This class should really be called _DisposingTicker or some such, but this
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
import 'dart:ui' as ui; import 'dart:ui' as ui;
import 'package:flutter/semantics.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/animation.dart'; import 'package:flutter/animation.dart';
import 'package:flutter/scheduler.dart'; import 'package:flutter/scheduler.dart';
...@@ -581,16 +582,17 @@ void main() { ...@@ -581,16 +582,17 @@ void main() {
group('AnimationBehavior', () { group('AnimationBehavior', () {
test('Default values for constructor', () { test('Default values for constructor', () {
final AnimationController controller = new AnimationController(vsync: const TestVSync(disableAnimations: true)); final AnimationController controller = new AnimationController(vsync: const TestVSync());
expect(controller.animationBehavior, AnimationBehavior.normal); expect(controller.animationBehavior, AnimationBehavior.normal);
final AnimationController repeating = new AnimationController.unbounded(vsync: const TestVSync(disableAnimations: true)); final AnimationController repeating = new AnimationController.unbounded(vsync: const TestVSync());
expect(repeating.animationBehavior, AnimationBehavior.preserve); expect(repeating.animationBehavior, AnimationBehavior.preserve);
}); });
test('AnimationBehavior.preserve runs at normal speed when animatingTo', () async { test('AnimationBehavior.preserve runs at normal speed when animatingTo', () async {
debugSemanticsDisableAnimations = true;
final AnimationController controller = new AnimationController( final AnimationController controller = new AnimationController(
vsync: const TestVSync(disableAnimations: true), vsync: const TestVSync(),
animationBehavior: AnimationBehavior.preserve, animationBehavior: AnimationBehavior.preserve,
); );
...@@ -609,11 +611,13 @@ void main() { ...@@ -609,11 +611,13 @@ void main() {
expect(controller.value, 1.0); expect(controller.value, 1.0);
expect(controller.status, AnimationStatus.completed); expect(controller.status, AnimationStatus.completed);
debugSemanticsDisableAnimations = false;
}); });
test('AnimationBehavior.normal runs at 20x speed when animatingTo', () async { test('AnimationBehavior.normal runs at 20x speed when animatingTo', () async {
debugSemanticsDisableAnimations = true;
final AnimationController controller = new AnimationController( final AnimationController controller = new AnimationController(
vsync: const TestVSync(disableAnimations: true), vsync: const TestVSync(),
animationBehavior: AnimationBehavior.normal, animationBehavior: AnimationBehavior.normal,
); );
...@@ -632,14 +636,16 @@ void main() { ...@@ -632,14 +636,16 @@ void main() {
expect(controller.value, 1.0); expect(controller.value, 1.0);
expect(controller.status, AnimationStatus.completed); expect(controller.status, AnimationStatus.completed);
debugSemanticsDisableAnimations = null;
}); });
test('AnimationBehavior.normal runs "faster" whan AnimationBehavior.preserve', () { test('AnimationBehavior.normal runs "faster" whan AnimationBehavior.preserve', () {
debugSemanticsDisableAnimations = true;
final AnimationController controller = new AnimationController( final AnimationController controller = new AnimationController(
vsync: const TestVSync(disableAnimations: true), vsync: const TestVSync(),
); );
final AnimationController fastController = new AnimationController( final AnimationController fastController = new AnimationController(
vsync: const TestVSync(disableAnimations: true), vsync: const TestVSync(),
); );
controller.fling(velocity: 1.0, animationBehavior: AnimationBehavior.preserve); controller.fling(velocity: 1.0, animationBehavior: AnimationBehavior.preserve);
...@@ -649,6 +655,7 @@ void main() { ...@@ -649,6 +655,7 @@ void main() {
// We don't assert a specific faction that normal animation. // We don't assert a specific faction that normal animation.
expect(controller.value < fastController.value, true); expect(controller.value < fastController.value, true);
debugSemanticsDisableAnimations = null;
}); });
}); });
} }
...@@ -273,9 +273,6 @@ class _FakeTicker implements Ticker { ...@@ -273,9 +273,6 @@ class _FakeTicker implements Ticker {
@override @override
bool get shouldScheduleTick => null; bool get shouldScheduleTick => null;
@override
bool disableAnimations = false;
@override @override
void dispose() {} void dispose() {}
......
...@@ -10,16 +10,8 @@ import 'package:flutter/scheduler.dart'; ...@@ -10,16 +10,8 @@ import 'package:flutter/scheduler.dart';
/// tree. /// tree.
class TestVSync implements TickerProvider { class TestVSync implements TickerProvider {
/// Creates a ticker provider that creates standalone tickers. /// Creates a ticker provider that creates standalone tickers.
const TestVSync({this.disableAnimations = false}); const TestVSync();
/// Whether to disable the animations of tickers create from this picker.
///
/// See also:
///
/// * [AccessibilityFeatures.disableAnimations], for the setting that controls this flag.
/// * [AnimationBehavior], for how animation controllers change when created from tickers with this flag.
final bool disableAnimations;
@override @override
Ticker createTicker(TickerCallback onTick) => new Ticker(onTick)..disableAnimations = disableAnimations; Ticker createTicker(TickerCallback onTick) => new Ticker(onTick);
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment