Revert "Automatic focus highlight mode for FocusManager (#37825)" (#38866)
This reverts commit a11d73148c90dd2980f0ab5a2d88159269937e3a because of a regression in
flutter_gallery_ios32__transition_perf's 90th_percentile_frame_build_time_millis.
Fixes #38860.
diff --git a/packages/flutter/lib/src/material/ink_well.dart b/packages/flutter/lib/src/material/ink_well.dart
index 5c261d3..91e2db5 100644
--- a/packages/flutter/lib/src/material/ink_well.dart
+++ b/packages/flutter/lib/src/material/ink_well.dart
@@ -478,7 +478,6 @@
_focusNode?.removeListener(_handleFocusUpdate);
_focusNode = Focus.of(context, nullOk: true);
_focusNode?.addListener(_handleFocusUpdate);
- WidgetsBinding.instance.focusManager.addHighlightModeListener(_handleFocusHighlightModeChange);
}
@override
@@ -492,7 +491,6 @@
@override
void dispose() {
- WidgetsBinding.instance.focusManager.removeHighlightModeListener(_handleFocusHighlightModeChange);
_focusNode?.removeListener(_handleFocusUpdate);
super.dispose();
}
@@ -610,25 +608,8 @@
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 4a80870..07f41ff 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 @@
/// 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 @@
}
}
-/// 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 @@
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<ValueChanged<FocusHighlightMode>> _listeners;
-
- /// Register a closure to be called when the [FocusManager] notifies its listeners
- /// that the value of [highlightMode] has changed.
- void addHighlightModeListener(ValueChanged<FocusHighlightMode> listener) {
- _listeners ??= ObserverList<ValueChanged<FocusHighlightMode>>();
- _listeners.add(listener);
- }
-
- /// Remove a previously registered closure from the list of closures that the
- /// [FocusManager] notifies.
- void removeHighlightModeListener(ValueChanged<FocusHighlightMode> listener) {
- _listeners?.remove(listener);
- }
-
- void _notifyHighlightModeListeners() {
- if (_listeners != null) {
- final List<ValueChanged<FocusHighlightMode>> localListeners = List<ValueChanged<FocusHighlightMode>>.from(_listeners);
- for (ValueChanged<FocusHighlightMode> 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<FocusManager>(
- 'The $runtimeType sending notification was',
- this,
- style: DiagnosticsTreeStyle.errorProperty,
- );
- },
- ));
- }
- }
- }
}
/// The root [FocusScopeNode] in the focus tree.
@@ -1200,33 +1038,7 @@
/// 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 b730a7d..ea223af 100644
--- a/packages/flutter/lib/src/widgets/framework.dart
+++ b/packages/flutter/lib/src/widgets/framework.dart
@@ -2176,14 +2176,7 @@
/// 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 99ae3b0..5589e38 100644
--- a/packages/flutter/test/material/buttons_test.dart
+++ b/packages/flutter/test/material/buttons_test.dart
@@ -406,8 +406,6 @@
),
),
);
-
- WidgetsBinding.instance.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
focusNode.requestFocus();
await tester.pumpAndSettle();
@@ -499,7 +497,6 @@
),
);
await tester.pumpAndSettle();
- WidgetsBinding.instance.focusManager.highlightStrategy = FocusHighlightStrategy.alwaysTraditional;
// Base elevation
Material material = tester.widget<Material>(rawButtonMaterial);
diff --git a/packages/flutter/test/material/ink_well_test.dart b/packages/flutter/test/material/ink_well_test.dart
index 73a4543..b9418ff 100644
--- a/packages/flutter/test/material/ink_well_test.dart
+++ b/packages/flutter/test/material/ink_well_test.dart
@@ -121,7 +121,6 @@
});
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 @@
..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 8ba1139..da4a1df 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 @@
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 @@
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 8e9b112..0db8db5 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 @@
// 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(<String, dynamic>{
- '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(