diff --git a/packages/flutter/lib/src/material/ink_well.dart b/packages/flutter/lib/src/material/ink_well.dart index 5c261d338b..91e2db5171 100644 --- a/packages/flutter/lib/src/material/ink_well.dart +++ b/packages/flutter/lib/src/material/ink_well.dart @@ -478,7 +478,6 @@ class _InkResponseState extends State with AutomaticKe _focusNode?.removeListener(_handleFocusUpdate); _focusNode = Focus.of(context, nullOk: true); _focusNode?.addListener(_handleFocusUpdate); - WidgetsBinding.instance.focusManager.addHighlightModeListener(_handleFocusHighlightModeChange); } @override @@ -492,7 +491,6 @@ class _InkResponseState extends State with AutomaticKe @override void dispose() { - WidgetsBinding.instance.focusManager.removeHighlightModeListener(_handleFocusHighlightModeChange); _focusNode?.removeListener(_handleFocusUpdate); super.dispose(); } @@ -610,25 +608,8 @@ class _InkResponseState extends State with AutomaticKe return splash; } - void _handleFocusHighlightModeChange(FocusHighlightMode mode) { - if (!mounted) { - return; - } - setState(() { - _handleFocusUpdate(); - }); - } - void _handleFocusUpdate() { - bool showFocus; - switch (WidgetsBinding.instance.focusManager.highlightMode) { - case FocusHighlightMode.touch: - showFocus = false; - break; - case FocusHighlightMode.traditional: - showFocus = enabled && (Focus.of(context, nullOk: true)?.hasPrimaryFocus ?? false); - break; - } + final bool showFocus = enabled && (Focus.of(context, nullOk: true)?.hasPrimaryFocus ?? false); updateHighlight(_HighlightType.focus, value: showFocus); } diff --git a/packages/flutter/lib/src/widgets/focus_manager.dart b/packages/flutter/lib/src/widgets/focus_manager.dart index 4a80870b65..07f41ff990 100644 --- a/packages/flutter/lib/src/widgets/focus_manager.dart +++ b/packages/flutter/lib/src/widgets/focus_manager.dart @@ -3,12 +3,10 @@ // found in the LICENSE file. import 'dart:async'; -import 'dart:io'; import 'dart:ui'; import 'package:flutter/foundation.dart'; import 'package:flutter/painting.dart'; -import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'binding.dart'; @@ -552,9 +550,6 @@ class FocusNode with DiagnosticableTreeMixin, ChangeNotifier { /// This object notifies its listeners whenever this value changes. bool get hasPrimaryFocus => _manager?.primaryFocus == this; - /// Returns the [FocusHighlightMode] that is currently in effect for this node. - FocusHighlightMode get highlightMode => WidgetsBinding.instance.focusManager.highlightMode; - /// Returns the nearest enclosing scope node above this node, including /// this node, if it's a scope. /// @@ -997,40 +992,6 @@ class FocusScopeNode extends FocusNode { } } -/// An enum to describe which kind of focus highlight behavior to use when -/// displaying focus information. -enum FocusHighlightMode { - /// Touch interfaces will not show the focus highlight except for controls - /// which bring up the soft keyboard. - /// - /// If a device that uses a traditional mouse and keyboard has a touch screen - /// attached, it can also enter `touch` mode if the user is using the touch - /// screen. - touch, - - /// Traditional interfaces (keyboard and mouse) will show the currently - /// focused control via a focus highlight of some sort. - /// - /// If a touch device (like a mobile phone) has a keyboard and/or mouse - /// attached, it also can enter `traditional` mode if the user is using these - /// input devices. - traditional, -} - -/// An enum to describe how the current value of [FocusManager.highlightMode] is -/// determined. The strategy is set on [FocusManager.highlightStrategy]. -enum FocusHighlightStrategy { - /// Automatic switches between the various highlight modes based on the last - /// kind of input that was received. This is the default. - automatic, - - /// [FocusManager.highlightMode] always returns [FocusHighlightMode.touch]. - alwaysTouch, - - /// [FocusManager.highlightMode] always returns [FocusHighlightMode.traditional]. - alwaysTraditional, -} - /// Manages the focus tree. /// /// The focus tree keeps track of which [FocusNode] is the user's current @@ -1069,129 +1030,6 @@ class FocusManager with DiagnosticableTreeMixin { FocusManager() { rootScope._manager = this; RawKeyboard.instance.addListener(_handleRawKeyEvent); - RendererBinding.instance.pointerRouter.addGlobalRoute(_handlePointerEvent); - } - - bool _lastInteractionWasTouch = true; - - /// Sets the strategy by which [highlightMode] is determined. - /// - /// If set to [FocusHighlightStrategy.automatic], then the highlight mode will - /// change depending upon the interaction mode used last. For instance, if the - /// last interaction was a touch interaction, then [highlightMode] will return - /// [FocusHighlightMode.touch], and focus highlights will only appear on - /// widgets that bring up a soft keyboard. If the last interaction was a - /// non-touch interaction (hardware keyboard press, mouse click, etc.), then - /// [highlightMode] will return [FocusHighlightMode.traditional], and focus - /// highlights will appear on all widgets. - /// - /// If set to [FocusHighlightStrategy.alwaysTouch] or - /// [FocusHighlightStrategy.alwaysTraditional], then [highlightMode] will - /// always return [FocusHighlightMode.touch] or - /// [FocusHighlightMode.traditional], respectively, regardless of the last UI - /// interaction type. - /// - /// The initial value of [highlightMode] depends upon the value of - /// [defaultTargetPlatform] and - /// [RendererBinding.instance.mouseTracker.mouseIsConnected], making a guess - /// about which interaction is most appropriate for the initial interaction - /// mode. - /// - /// Defaults to [FocusHighlightStrategy.automatic]. - FocusHighlightStrategy get highlightStrategy => _highlightStrategy; - FocusHighlightStrategy _highlightStrategy = FocusHighlightStrategy.automatic; - set highlightStrategy(FocusHighlightStrategy highlightStrategy) { - _highlightStrategy = highlightStrategy; - _updateHighlightMode(); - } - - /// Indicates the current interaction mode for focus highlights. - /// - /// The value returned depends upon the [highlightStrategy] used, and possibly - /// (depending on the value of [highlightStrategy]) the most recent - /// interaction mode that they user used. - /// - /// If [highlightMode] returns [FocusHighlightMode.touch], then widgets should - /// not draw their focus highlight unless they perform text entry. - /// - /// If [highlightMode] returns [FocusHighlightMode.traditional], then widgets should - /// draw their focus highlight whenever they are focused. - FocusHighlightMode get highlightMode => _highlightMode; - FocusHighlightMode _highlightMode = FocusHighlightMode.touch; - - // Update function to be called whenever the state relating to highlightMode - // changes. - void _updateHighlightMode() { - // Assume that if we're on one of these mobile platforms, or if there's no - // mouse connected, that the initial interaction will be touch-based, and - // that it's traditional mouse and keyboard on all others. - // - // This only affects the initial value: the ongoing value is updated as soon - // as any input events are received. - _lastInteractionWasTouch ??= Platform.isAndroid || Platform.isIOS || !WidgetsBinding.instance.mouseTracker.mouseIsConnected; - FocusHighlightMode newMode; - switch (highlightStrategy) { - case FocusHighlightStrategy.automatic: - if (_lastInteractionWasTouch) { - newMode = FocusHighlightMode.touch; - } else { - newMode = FocusHighlightMode.traditional; - } - break; - case FocusHighlightStrategy.alwaysTouch: - newMode = FocusHighlightMode.touch; - break; - case FocusHighlightStrategy.alwaysTraditional: - newMode = FocusHighlightMode.traditional; - break; - } - if (newMode != _highlightMode) { - _highlightMode = newMode; - _notifyHighlightModeListeners(); - } - } - - // The list of listeners for [highlightMode] state changes. - ObserverList> _listeners; - - /// Register a closure to be called when the [FocusManager] notifies its listeners - /// that the value of [highlightMode] has changed. - void addHighlightModeListener(ValueChanged listener) { - _listeners ??= ObserverList>(); - _listeners.add(listener); - } - - /// Remove a previously registered closure from the list of closures that the - /// [FocusManager] notifies. - void removeHighlightModeListener(ValueChanged listener) { - _listeners?.remove(listener); - } - - void _notifyHighlightModeListeners() { - if (_listeners != null) { - final List> localListeners = List>.from(_listeners); - for (ValueChanged listener in localListeners) { - try { - if (_listeners.contains(listener)) { - listener(_highlightMode); - } - } catch (exception, stack) { - FlutterError.reportError(FlutterErrorDetails( - exception: exception, - stack: stack, - library: 'widgets library', - context: ErrorDescription('while dispatching notifications for $runtimeType'), - informationCollector: () sync* { - yield DiagnosticsProperty( - 'The $runtimeType sending notification was', - this, - style: DiagnosticsTreeStyle.errorProperty, - ); - }, - )); - } - } - } } /// The root [FocusScopeNode] in the focus tree. @@ -1200,33 +1038,7 @@ class FocusManager with DiagnosticableTreeMixin { /// for a given [FocusNode], call [FocusNode.nearestScope]. final FocusScopeNode rootScope = FocusScopeNode(debugLabel: 'Root Focus Scope'); - void _handlePointerEvent(PointerEvent event) { - bool newState; - switch (event.kind) { - case PointerDeviceKind.touch: - case PointerDeviceKind.stylus: - case PointerDeviceKind.invertedStylus: - newState = true; - break; - case PointerDeviceKind.mouse: - case PointerDeviceKind.unknown: - newState = false; - break; - } - if (_lastInteractionWasTouch != newState) { - _lastInteractionWasTouch = newState; - _updateHighlightMode(); - } - } - void _handleRawKeyEvent(RawKeyEvent event) { - // Update this first, since things responding to the keys might look at the - // highlight mode, and it should be accurate. - if (_lastInteractionWasTouch) { - _lastInteractionWasTouch = false; - _updateHighlightMode(); - } - // Walk the current focus from the leaf to the root, calling each one's // onKey on the way up, and if one responds that they handled it, stop. if (_primaryFocus == null) { diff --git a/packages/flutter/lib/src/widgets/framework.dart b/packages/flutter/lib/src/widgets/framework.dart index b730a7d271..ea223af260 100644 --- a/packages/flutter/lib/src/widgets/framework.dart +++ b/packages/flutter/lib/src/widgets/framework.dart @@ -2176,14 +2176,7 @@ class BuildOwner { /// the [FocusScopeNode] for a given [BuildContext]. /// /// See [FocusManager] for more details. - FocusManager get focusManager { - _focusManager ??= FocusManager(); - return _focusManager; - } - FocusManager _focusManager; - set focusManager(FocusManager focusManager) { - _focusManager = focusManager; - } + FocusManager focusManager = FocusManager(); /// Adds an element to the dirty elements list so that it will be rebuilt /// when [WidgetsBinding.drawFrame] calls [buildScope]. diff --git a/packages/flutter/test/material/buttons_test.dart b/packages/flutter/test/material/buttons_test.dart index 99ae3b08a2..5589e38395 100644 --- a/packages/flutter/test/material/buttons_test.dart +++ b/packages/flutter/test/material/buttons_test.dart @@ -406,8 +406,6 @@ void main() { ), ), ); - - WidgetsBinding.instance.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; focusNode.requestFocus(); await tester.pumpAndSettle(); @@ -499,7 +497,6 @@ void main() { ), ); await tester.pumpAndSettle(); - WidgetsBinding.instance.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; // Base elevation Material material = tester.widget(rawButtonMaterial); diff --git a/packages/flutter/test/material/ink_well_test.dart b/packages/flutter/test/material/ink_well_test.dart index 73a4543873..b9418ff0e5 100644 --- a/packages/flutter/test/material/ink_well_test.dart +++ b/packages/flutter/test/material/ink_well_test.dart @@ -121,7 +121,6 @@ void main() { }); testWidgets('ink response changes color on focus', (WidgetTester tester) async { - WidgetsBinding.instance.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; final FocusNode focusNode = FocusNode(debugLabel: 'Ink Focus'); await tester.pumpWidget(Material( child: Directionality( @@ -155,40 +154,6 @@ void main() { ..rect(rect: const Rect.fromLTRB(350.0, 250.0, 450.0, 350.0), color: const Color(0xff0000ff))); }); - testWidgets("ink response doesn't change color on focus when on touch device", (WidgetTester tester) async { - WidgetsBinding.instance.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTouch; - final FocusNode focusNode = FocusNode(debugLabel: 'Ink Focus'); - await tester.pumpWidget(Material( - child: Directionality( - textDirection: TextDirection.ltr, - child: Center( - child: Focus( - focusNode: focusNode, - child: Container( - width: 100, - height: 100, - child: InkWell( - hoverColor: const Color(0xff00ff00), - splashColor: const Color(0xffff0000), - focusColor: const Color(0xff0000ff), - highlightColor: const Color(0xf00fffff), - onTap: () {}, - onLongPress: () {}, - onHover: (bool hover) {} - ), - ), - ), - ), - ), - )); - await tester.pumpAndSettle(); - final RenderObject inkFeatures = tester.allRenderObjects.firstWhere((RenderObject object) => object.runtimeType.toString() == '_RenderInkFeatures'); - expect(inkFeatures, paintsExactlyCountTimes(#rect, 0)); - focusNode.requestFocus(); - await tester.pumpAndSettle(); - expect(inkFeatures, paintsExactlyCountTimes(#rect, 0)); - }); - group('feedback', () { FeedbackTester feedback; diff --git a/packages/flutter/test/material/raw_material_button_test.dart b/packages/flutter/test/material/raw_material_button_test.dart index 8ba113911d..da4a1df52a 100644 --- a/packages/flutter/test/material/raw_material_button_test.dart +++ b/packages/flutter/test/material/raw_material_button_test.dart @@ -215,7 +215,6 @@ void main() { const Key key = Key('test'); const Color focusColor = Color(0xff00ff00); - WidgetsBinding.instance.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; await tester.pumpWidget( MaterialApp( home: Center( @@ -242,7 +241,6 @@ void main() { const Key key = Key('test'); const Color hoverColor = Color(0xff00ff00); - WidgetsBinding.instance.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; await tester.pumpWidget( MaterialApp( home: Center( diff --git a/packages/flutter/test/widgets/focus_manager_test.dart b/packages/flutter/test/widgets/focus_manager_test.dart index 8e9b112a7c..0db8db5fab 100644 --- a/packages/flutter/test/widgets/focus_manager_test.dart +++ b/packages/flutter/test/widgets/focus_manager_test.dart @@ -5,7 +5,6 @@ import 'dart:typed_data'; import 'package:flutter/foundation.dart'; -import 'package:flutter/gestures.dart'; import 'package:flutter/services.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -484,55 +483,6 @@ void main() { // receive it. expect(receivedAnEvent, isEmpty); }); - testWidgets('Events change focus highlight mode.', (WidgetTester tester) async { - await setupWidget(tester); - int callCount = 0; - FocusHighlightMode lastMode; - void handleModeChange(FocusHighlightMode mode) { - lastMode = mode; - callCount++; - } - - final FocusManager focusManager = WidgetsBinding.instance.focusManager; - focusManager.addHighlightModeListener(handleModeChange); - addTearDown(() => focusManager.removeHighlightModeListener(handleModeChange)); - expect(callCount, equals(0)); - expect(lastMode, isNull); - focusManager.highlightStrategy = FocusHighlightStrategy.automatic; - expect(focusManager.highlightMode, equals(FocusHighlightMode.touch)); - sendFakeKeyEvent({ - 'type': 'keydown', - 'keymap': 'fuchsia', - 'hidUsage': 0x04, - 'codePoint': 0x64, - 'modifiers': RawKeyEventDataFuchsia.modifierLeftMeta, - }); - expect(callCount, equals(1)); - expect(lastMode, FocusHighlightMode.traditional); - expect(focusManager.highlightMode, equals(FocusHighlightMode.traditional)); - await tester.tap(find.byType(Container)); - expect(callCount, equals(2)); - expect(lastMode, FocusHighlightMode.touch); - expect(focusManager.highlightMode, equals(FocusHighlightMode.touch)); - final TestGesture gesture = await tester.startGesture(Offset.zero, kind: PointerDeviceKind.mouse); - addTearDown(gesture.removePointer); - await gesture.up(); - expect(callCount, equals(3)); - expect(lastMode, FocusHighlightMode.traditional); - expect(focusManager.highlightMode, equals(FocusHighlightMode.traditional)); - await tester.tap(find.byType(Container)); - expect(callCount, equals(4)); - expect(lastMode, FocusHighlightMode.touch); - expect(focusManager.highlightMode, equals(FocusHighlightMode.touch)); - focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional; - expect(callCount, equals(5)); - expect(lastMode, FocusHighlightMode.traditional); - expect(focusManager.highlightMode, equals(FocusHighlightMode.traditional)); - focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTouch; - expect(callCount, equals(6)); - expect(lastMode, FocusHighlightMode.touch); - expect(focusManager.highlightMode, equals(FocusHighlightMode.touch)); - }); testWidgets('implements debugFillProperties', (WidgetTester tester) async { final DiagnosticPropertiesBuilder builder = DiagnosticPropertiesBuilder(); FocusScopeNode(