"Fossies" - the Fresh Open Source Software Archive

Member "flutter-1.22.4/packages/flutter/lib/src/widgets/focus_manager.dart" (13 Nov 2020, 72931 Bytes) of package /linux/misc/flutter-1.22.4.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Dart source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 // Copyright 2014 The Flutter Authors. All rights reserved.
    2 // Use of this source code is governed by a BSD-style license that can be
    3 // found in the LICENSE file.
    4 
    5 // @dart = 2.8
    6 
    7 import 'dart:async';
    8 import 'dart:ui';
    9 
   10 import 'package:flutter/foundation.dart';
   11 import 'package:flutter/gestures.dart';
   12 import 'package:flutter/painting.dart';
   13 import 'package:flutter/services.dart';
   14 
   15 import 'binding.dart';
   16 import 'focus_scope.dart';
   17 import 'focus_traversal.dart';
   18 import 'framework.dart';
   19 
   20 // Used for debugging focus code. Set to true to see highly verbose debug output
   21 // when focus changes occur.
   22 const bool _kDebugFocus = false;
   23 
   24 bool _focusDebug(String message, [Iterable<String> details]) {
   25   if (_kDebugFocus) {
   26     debugPrint('FOCUS: $message');
   27     if (details != null && details.isNotEmpty) {
   28       for (final String detail in details) {
   29         debugPrint('    $detail');
   30       }
   31     }
   32   }
   33   return true;
   34 }
   35 
   36 /// Signature of a callback used by [Focus.onKey] and [FocusScope.onKey]
   37 /// to receive key events.
   38 ///
   39 /// The [node] is the node that received the event.
   40 typedef FocusOnKeyCallback = bool Function(FocusNode node, RawKeyEvent event);
   41 
   42 /// An attachment point for a [FocusNode].
   43 ///
   44 /// Using a [FocusAttachment] is rarely needed, unless you are building
   45 /// something akin to the [Focus] or [FocusScope] widgets from scratch.
   46 ///
   47 /// Once created, a [FocusNode] must be attached to the widget tree by its
   48 /// _host_ [StatefulWidget] via a [FocusAttachment] object. [FocusAttachment]s
   49 /// are owned by the [StatefulWidget] that hosts a [FocusNode] or
   50 /// [FocusScopeNode]. There can be multiple [FocusAttachment]s for each
   51 /// [FocusNode], but the node will only ever be attached to one of them at a
   52 /// time.
   53 ///
   54 /// This attachment is created by calling [FocusNode.attach], usually from the
   55 /// host widget's [State.initState] method. If the widget is updated to have a
   56 /// different focus node, then the new node needs to be attached in
   57 /// [State.didUpdateWidget], after calling [detach] on the previous
   58 /// [FocusAttachment]. Once detached, the attachment is defunct and will no
   59 /// longer make changes to the [FocusNode] through [reparent].
   60 ///
   61 /// Without these attachment points, it would be possible for a focus node to
   62 /// simultaneously be attached to more than one part of the widget tree during
   63 /// the build stage.
   64 class FocusAttachment {
   65   /// A private constructor, because [FocusAttachment]s are only to be created
   66   /// by [FocusNode.attach].
   67   FocusAttachment._(this._node) : assert(_node != null);
   68 
   69   // The focus node that this attachment manages an attachment for. The node may
   70   // not yet have a parent, or may have been detached from this attachment, so
   71   // don't count on this node being in a usable state.
   72   final FocusNode _node;
   73 
   74   /// Returns true if the associated node is attached to this attachment.
   75   ///
   76   /// It is possible to be attached to the widget tree, but not be placed in
   77   /// the focus tree (i.e. to not have a parent yet in the focus tree).
   78   bool get isAttached => _node._attachment == this;
   79 
   80   /// Detaches the [FocusNode] this attachment point is associated with from the
   81   /// focus tree, and disconnects it from this attachment point.
   82   ///
   83   /// Calling [FocusNode.dispose] will also automatically detach the node.
   84   void detach() {
   85     assert(_node != null);
   86     assert(_focusDebug('Detaching node:', <String>[_node.toString(), 'With enclosing scope ${_node.enclosingScope}']));
   87     if (isAttached) {
   88       if (_node.hasPrimaryFocus || (_node._manager != null && _node._manager._markedForFocus == _node)) {
   89         _node.unfocus(disposition: UnfocusDisposition.previouslyFocusedChild);
   90       }
   91       // This node is no longer in the tree, so shouldn't send notifications anymore.
   92       _node._manager?._markDetached(_node);
   93       _node._parent?._removeChild(_node);
   94       _node._attachment = null;
   95       assert(!_node.hasPrimaryFocus);
   96       assert(_node._manager?._markedForFocus != _node);
   97     }
   98     assert(!isAttached);
   99   }
  100 
  101   /// Ensures that the [FocusNode] attached at this attachment point has the
  102   /// proper parent node, changing it if necessary.
  103   ///
  104   /// If given, ensures that the given [parent] node is the parent of the node
  105   /// that is attached at this attachment point, changing it if necessary.
  106   /// However, it is usually not necessary to supply an explicit parent, since
  107   /// [reparent] will use [Focus.of] to determine the correct parent node for
  108   /// the context given in [FocusNode.attach].
  109   ///
  110   /// If [isAttached] is false, then calling this method does nothing.
  111   ///
  112   /// Should be called whenever the associated widget is rebuilt in order to
  113   /// maintain the focus hierarchy.
  114   ///
  115   /// A [StatefulWidget] that hosts a [FocusNode] should call this method on the
  116   /// node it hosts during its [State.build] or [State.didChangeDependencies]
  117   /// methods in case the widget is moved from one location in the tree to
  118   /// another location that has a different [FocusScope] or context.
  119   ///
  120   /// The optional [parent] argument must be supplied when not using [Focus] and
  121   /// [FocusScope] widgets to build the focus tree, or if there is a need to
  122   /// supply the parent explicitly (which are both uncommon).
  123   void reparent({FocusNode parent}) {
  124     assert(_node != null);
  125     if (isAttached) {
  126       assert(_node.context != null);
  127       parent ??= Focus.of(_node.context, nullOk: true, scopeOk: true);
  128       parent ??= _node.context.owner.focusManager.rootScope;
  129       assert(parent != null);
  130       parent._reparent(_node);
  131     }
  132   }
  133 }
  134 
  135 /// Describe what should happen after [FocusNode.unfocus] is called.
  136 ///
  137 /// See also:
  138 ///
  139 ///  * [FocusNode.unfocus], which takes this as its `disposition` parameter.
  140 enum UnfocusDisposition {
  141   /// Focus the nearest focusable enclosing scope of this node, but do not
  142   /// descend to locate the leaf [FocusScopeNode.focusedChild] the way
  143   /// [previouslyFocusedChild] does.
  144   ///
  145   /// Focusing the scope in this way clears the [FocusScopeNode.focusedChild]
  146   /// history for the enclosing scope when it receives focus. Because of this,
  147   /// calling a traversal method like [FocusNode.nextFocus] after unfocusing
  148   /// will cause the [FocusTraversalPolicy] to pick the node it thinks should be
  149   /// first in the scope.
  150   ///
  151   /// This is the default disposition for [FocusNode.unfocus].
  152   scope,
  153 
  154   /// Focus the previously focused child of the nearest focusable enclosing
  155   /// scope of this node.
  156   ///
  157   /// If there is no previously focused child, then this is equivalent to
  158   /// using the [scope] disposition.
  159   ///
  160   /// Unfocusing with this disposition will cause [FocusNode.unfocus] to walk up
  161   /// the tree to the nearest focusable enclosing scope, then start to walk down
  162   /// the tree, looking for a focused child at its
  163   /// [FocusScopeNode.focusedChild].
  164   ///
  165   /// If the [FocusScopeNode.focusedChild] is a scope, then look for its
  166   /// [FocusScopeNode.focusedChild], and so on, finding the leaf
  167   /// [FocusScopeNode.focusedChild] that is not a scope, or, failing that, a
  168   /// leaf scope that has no focused child.
  169   previouslyFocusedChild,
  170 }
  171 
  172 /// An object that can be used by a stateful widget to obtain the keyboard focus
  173 /// and to handle keyboard events.
  174 ///
  175 /// _Please see the [Focus] and [FocusScope] widgets, which are utility widgets
  176 /// that manage their own [FocusNode]s and [FocusScopeNode]s, respectively. If
  177 /// they aren't appropriate, [FocusNode]s can be managed directly, but doing
  178 /// this yourself is rare._
  179 ///
  180 /// [FocusNode]s are persistent objects that form a _focus tree_ that is a
  181 /// representation of the widgets in the hierarchy that are interested in focus.
  182 /// A focus node might need to be created if it is passed in from an ancestor of
  183 /// a [Focus] widget to control the focus of the children from the ancestor, or
  184 /// a widget might need to host one if the widget subsystem is not being used,
  185 /// or if the [Focus] and [FocusScope] widgets provide insufficient control.
  186 ///
  187 /// [FocusNode]s are organized into _scopes_ (see [FocusScopeNode]), which form
  188 /// sub-trees of nodes that restrict traversal to a group of nodes. Within a
  189 /// scope, the most recent nodes to have focus are remembered, and if a node is
  190 /// focused and then unfocused, the previous node receives focus again.
  191 ///
  192 /// The focus node hierarchy can be traversed using the [parent], [children],
  193 /// [ancestors] and [descendants] accessors.
  194 ///
  195 /// [FocusNode]s are [ChangeNotifier]s, so a listener can be registered to
  196 /// receive a notification when the focus changes. If the [Focus] and
  197 /// [FocusScope] widgets are being used to manage the nodes, consider
  198 /// establishing an [InheritedWidget] dependency on them by calling [Focus.of]
  199 /// or [FocusScope.of] instead. [FocusNode.hasFocus] can also be used to
  200 /// establish a similar dependency, especially if all that is needed is to
  201 /// determine whether or not the widget is focused at build time.
  202 ///
  203 /// To see the focus tree in the debug console, call [debugDumpFocusTree]. To
  204 /// get the focus tree as a string, call [debugDescribeFocusTree].
  205 ///
  206 /// {@template flutter.widgets.focus_manager.focus.lifecycle}
  207 /// ## Lifecycle
  208 ///
  209 /// There are several actors involved in the lifecycle of a
  210 /// [FocusNode]/[FocusScopeNode]. They are created and disposed by their
  211 /// _owner_, attached, detached, and re-parented using a [FocusAttachment] by
  212 /// their _host_ (which must be owned by the [State] of a [StatefulWidget]), and
  213 /// they are managed by the [FocusManager]. Different parts of the [FocusNode]
  214 /// API are intended for these different actors.
  215 ///
  216 /// [FocusNode]s (and hence [FocusScopeNode]s) are persistent objects that form
  217 /// part of a _focus tree_ that is a sparse representation of the widgets in the
  218 /// hierarchy that are interested in receiving keyboard events. They must be
  219 /// managed like other persistent state, which is typically done by a
  220 /// [StatefulWidget] that owns the node. A stateful widget that owns a focus
  221 /// scope node must call [dispose] from its [State.dispose] method.
  222 ///
  223 /// Once created, a [FocusNode] must be attached to the widget tree via a
  224 /// [FocusAttachment] object. This attachment is created by calling [attach],
  225 /// usually from the [State.initState] method. If the hosting widget is updated
  226 /// to have a different focus node, then the updated node needs to be attached
  227 /// in [State.didUpdateWidget], after calling [FocusAttachment.detach] on the
  228 /// previous [FocusAttachment].
  229 ///
  230 /// Because [FocusNode]s form a sparse representation of the widget tree, they
  231 /// must be updated whenever the widget tree is rebuilt. This is done by calling
  232 /// [FocusAttachment.reparent], usually from the [State.build] or
  233 /// [State.didChangeDependencies] methods of the widget that represents the
  234 /// focused region, so that the [BuildContext] assigned to the [FocusScopeNode]
  235 /// can be tracked (the context is used to obtain the [RenderObject], from which
  236 /// the geometry of focused regions can be determined).
  237 ///
  238 /// Creating a [FocusNode] each time [State.build] is invoked will cause the
  239 /// focus to be lost each time the widget is built, which is usually not desired
  240 /// behavior (call [unfocus] if losing focus is desired).
  241 ///
  242 /// If, as is common, the hosting [StatefulWidget] is also the owner of the
  243 /// focus node, then it will also call [dispose] from its [State.dispose] (in
  244 /// which case the [FocusAttachment.detach] may be skipped, since dispose will
  245 /// automatically detach). If another object owns the focus node, then it must
  246 /// call [dispose] when the node is done being used.
  247 /// {@endtemplate}
  248 ///
  249 /// {@template flutter.widgets.focus_manager.focus.keyEvents}
  250 /// ## Key Event Propagation
  251 ///
  252 /// The [FocusManager] receives key events from [RawKeyboard] and will pass them
  253 /// to the focused nodes. It starts with the node with the primary focus, and
  254 /// will call the [onKey] callback for that node. If the callback returns false,
  255 /// indicating that it did not handle the event, the [FocusManager] will move to
  256 /// the parent of that node and call its [onKey]. If that [onKey] returns true,
  257 /// then it will stop propagating the event. If it reaches the root
  258 /// [FocusScopeNode], [FocusManager.rootScope], the event is discarded.
  259 /// {@endtemplate}
  260 ///
  261 /// ## Focus Traversal
  262 ///
  263 /// The term _traversal_, sometimes called _tab traversal_, refers to moving the
  264 /// focus from one widget to the next in a particular order (also sometimes
  265 /// referred to as the _tab order_, since the TAB key is often bound to the
  266 /// action to move to the next widget).
  267 ///
  268 /// To give focus to the logical _next_ or _previous_ widget in the UI, call the
  269 /// [nextFocus] or [previousFocus] methods. To give the focus to a widget in a
  270 /// particular direction, call the [focusInDirection] method.
  271 ///
  272 /// The policy for what the _next_ or _previous_ widget is, or the widget in a
  273 /// particular direction, is determined by the [FocusTraversalPolicy] in force.
  274 ///
  275 /// The ambient policy is determined by looking up the widget hierarchy for a
  276 /// [FocusTraversalGroup] widget, and obtaining the focus traversal policy from
  277 /// it. Different focus nodes can inherit difference policies, so part of the
  278 /// app can go in a predefined order (using [OrderedTraversalPolicy]), and part
  279 /// can go in reading order (using [ReadingOrderTraversalPolicy]), depending
  280 /// upon the use case.
  281 ///
  282 /// Predefined policies include [WidgetOrderTraversalPolicy],
  283 /// [ReadingOrderTraversalPolicy], [OrderedTraversalPolicy], and
  284 /// [DirectionalFocusTraversalPolicyMixin], but custom policies can be built
  285 /// based upon these policies. See [FocusTraversalPolicy] for more information.
  286 ///
  287 /// {@tool dartpad --template=stateless_widget_scaffold} This example shows how
  288 /// a FocusNode should be managed if not using the [Focus] or [FocusScope]
  289 /// widgets. See the [Focus] widget for a similar example using [Focus] and
  290 /// [FocusScope] widgets.
  291 ///
  292 /// ```dart imports
  293 /// import 'package:flutter/services.dart';
  294 /// ```
  295 ///
  296 /// ```dart preamble
  297 /// class ColorfulButton extends StatefulWidget {
  298 ///   ColorfulButton({Key key}) : super(key: key);
  299 ///
  300 ///   @override
  301 ///   _ColorfulButtonState createState() => _ColorfulButtonState();
  302 /// }
  303 ///
  304 /// class _ColorfulButtonState extends State<ColorfulButton> {
  305 ///   FocusNode _node;
  306 ///   bool _focused = false;
  307 ///   FocusAttachment _nodeAttachment;
  308 ///   Color _color = Colors.white;
  309 ///
  310 ///   @override
  311 ///   void initState() {
  312 ///     super.initState();
  313 ///     _node = FocusNode(debugLabel: 'Button');
  314 ///     _node.addListener(_handleFocusChange);
  315 ///     _nodeAttachment = _node.attach(context, onKey: _handleKeyPress);
  316 ///   }
  317 ///
  318 ///   void _handleFocusChange() {
  319 ///     if (_node.hasFocus != _focused) {
  320 ///       setState(() {
  321 ///         _focused = _node.hasFocus;
  322 ///       });
  323 ///     }
  324 ///   }
  325 ///
  326 ///   bool _handleKeyPress(FocusNode node, RawKeyEvent event) {
  327 ///     if (event is RawKeyDownEvent) {
  328 ///       print('Focus node ${node.debugLabel} got key event: ${event.logicalKey}');
  329 ///       if (event.logicalKey == LogicalKeyboardKey.keyR) {
  330 ///         print('Changing color to red.');
  331 ///         setState(() {
  332 ///           _color = Colors.red;
  333 ///         });
  334 ///         return true;
  335 ///       } else if (event.logicalKey == LogicalKeyboardKey.keyG) {
  336 ///         print('Changing color to green.');
  337 ///         setState(() {
  338 ///           _color = Colors.green;
  339 ///         });
  340 ///         return true;
  341 ///       } else if (event.logicalKey == LogicalKeyboardKey.keyB) {
  342 ///         print('Changing color to blue.');
  343 ///         setState(() {
  344 ///           _color = Colors.blue;
  345 ///         });
  346 ///         return true;
  347 ///       }
  348 ///     }
  349 ///     return false;
  350 ///   }
  351 ///
  352 ///   @override
  353 ///   void dispose() {
  354 ///     _node.removeListener(_handleFocusChange);
  355 ///     // The attachment will automatically be detached in dispose().
  356 ///     _node.dispose();
  357 ///     super.dispose();
  358 ///   }
  359 ///
  360 ///   @override
  361 ///   Widget build(BuildContext context) {
  362 ///     _nodeAttachment.reparent();
  363 ///     return GestureDetector(
  364 ///       onTap: () {
  365 ///         if (_focused) {
  366 ///             _node.unfocus();
  367 ///         } else {
  368 ///            _node.requestFocus();
  369 ///         }
  370 ///       },
  371 ///       child: Center(
  372 ///         child: Container(
  373 ///           width: 400,
  374 ///           height: 100,
  375 ///           color: _focused ? _color : Colors.white,
  376 ///           alignment: Alignment.center,
  377 ///           child: Text(
  378 ///               _focused ? "I'm in color! Press R,G,B!" : 'Press to focus'),
  379 ///         ),
  380 ///       ),
  381 ///     );
  382 ///   }
  383 /// }
  384 /// ```
  385 ///
  386 /// ```dart
  387 /// Widget build(BuildContext context) {
  388 ///   final TextTheme textTheme = Theme.of(context).textTheme;
  389 ///   return DefaultTextStyle(
  390 ///     style: textTheme.headline4,
  391 ///     child: ColorfulButton(),
  392 ///   );
  393 /// }
  394 /// ```
  395 /// {@end-tool}
  396 ///
  397 /// See also:
  398 ///
  399 /// * [Focus], a widget that manages a [FocusNode] and provides access to focus
  400 ///   information and actions to its descendant widgets.
  401 /// * [FocusTraversalGroup], a widget used to group together and configure the
  402 ///   focus traversal policy for a widget subtree.
  403 /// * [FocusManager], a singleton that manages the primary focus and distributes
  404 ///   key events to focused nodes.
  405 /// * [FocusTraversalPolicy], a class used to determine how to move the focus to
  406 ///   other nodes.
  407 class FocusNode with DiagnosticableTreeMixin, ChangeNotifier {
  408   /// Creates a focus node.
  409   ///
  410   /// The [debugLabel] is ignored on release builds.
  411   ///
  412   /// The [skipTraversal], [descendantsAreFocusable], and [canRequestFocus]
  413   /// arguments must not be null.
  414   FocusNode({
  415     String debugLabel,
  416     FocusOnKeyCallback onKey,
  417     bool skipTraversal = false,
  418     bool canRequestFocus = true,
  419     bool descendantsAreFocusable = true,
  420   })  : assert(skipTraversal != null),
  421         assert(canRequestFocus != null),
  422         assert(descendantsAreFocusable != null),
  423         _skipTraversal = skipTraversal,
  424         _canRequestFocus = canRequestFocus,
  425         _descendantsAreFocusable = descendantsAreFocusable,
  426         _onKey = onKey {
  427     // Set it via the setter so that it does nothing on release builds.
  428     this.debugLabel = debugLabel;
  429   }
  430 
  431   /// If true, tells the focus traversal policy to skip over this node for
  432   /// purposes of the traversal algorithm.
  433   ///
  434   /// This may be used to place nodes in the focus tree that may be focused, but
  435   /// not traversed, allowing them to receive key events as part of the focus
  436   /// chain, but not be traversed to via focus traversal.
  437   ///
  438   /// This is different from [canRequestFocus] because it only implies that the
  439   /// node can't be reached via traversal, not that it can't be focused. It may
  440   /// still be focused explicitly.
  441   bool get skipTraversal => _skipTraversal;
  442   bool _skipTraversal;
  443   set skipTraversal(bool value) {
  444     if (value != _skipTraversal) {
  445       _skipTraversal = value;
  446       _manager?._markPropertiesChanged(this);
  447     }
  448   }
  449 
  450   /// If true, this focus node may request the primary focus.
  451   ///
  452   /// Defaults to true.  Set to false if you want this node to do nothing when
  453   /// [requestFocus] is called on it.
  454   ///
  455   /// If set to false on a [FocusScopeNode], will cause all of the children of
  456   /// the scope node to not be focusable.
  457   ///
  458   /// If set to false on a [FocusNode], it will not affect the children of the
  459   /// node.
  460   ///
  461   /// The [hasFocus] member can still return true if this node is the ancestor
  462   /// of a node with primary focus.
  463   ///
  464   /// This is different than [skipTraversal] because [skipTraversal] still
  465   /// allows the node to be focused, just not traversed to via the
  466   /// [FocusTraversalPolicy]
  467   ///
  468   /// Setting [canRequestFocus] to false implies that the node will also be
  469   /// skipped for traversal purposes.
  470   ///
  471   /// See also:
  472   ///
  473   ///  * [FocusTraversalGroup], a widget used to group together and configure the
  474   ///    focus traversal policy for a widget subtree.
  475   ///  * [FocusTraversalPolicy], a class that can be extended to describe a
  476   ///    traversal policy.
  477   bool get canRequestFocus {
  478     if (!_canRequestFocus) {
  479       return false;
  480     }
  481     final FocusScopeNode scope = enclosingScope;
  482     if (scope != null && !scope.canRequestFocus) {
  483       return false;
  484     }
  485     for (final FocusNode ancestor in ancestors) {
  486       if (!ancestor.descendantsAreFocusable) {
  487         return false;
  488       }
  489     }
  490     return true;
  491   }
  492 
  493   bool _canRequestFocus;
  494   @mustCallSuper
  495   set canRequestFocus(bool value) {
  496     if (value != _canRequestFocus) {
  497       // Have to set this first before unfocusing, since it checks this to cull
  498       // unfocusable, previously-focused children.
  499       _canRequestFocus = value;
  500       if (hasFocus && !value) {
  501         unfocus(disposition: UnfocusDisposition.previouslyFocusedChild);
  502       }
  503       _manager?._markPropertiesChanged(this);
  504     }
  505   }
  506 
  507   /// If false, will disable focus for all of this node's descendants.
  508   ///
  509   /// Defaults to true. Does not affect focusability of this node: for that,
  510   /// use [canRequestFocus].
  511   ///
  512   /// If any descendants are focused when this is set to false, they will be
  513   /// unfocused. When `descendantsAreFocusable` is set to true again, they will
  514   /// not be refocused, although they will be able to accept focus again.
  515   ///
  516   /// Does not affect the value of [canRequestFocus] on the descendants.
  517   ///
  518   /// If a descendant node loses focus when this value is changed, the focus
  519   /// will move to the scope enclosing this node.
  520   ///
  521   /// See also:
  522   ///
  523   ///  * [ExcludeFocus], a widget that uses this property to conditionally
  524   ///    exclude focus for a subtree.
  525   ///  * [Focus], a widget that exposes this setting as a parameter.
  526   ///  * [FocusTraversalGroup], a widget used to group together and configure
  527   ///    the focus traversal policy for a widget subtree that also has an
  528   ///    `descendantsAreFocusable` parameter that prevents its children from
  529   ///    being focused.
  530   bool get descendantsAreFocusable => _descendantsAreFocusable;
  531   bool _descendantsAreFocusable;
  532   @mustCallSuper
  533   set descendantsAreFocusable(bool value) {
  534     if (value == _descendantsAreFocusable) {
  535       return;
  536     }
  537     // Set _descendantsAreFocusable before unfocusing, so the scope won't try
  538     // and focus any of the children here again if it is false.
  539     _descendantsAreFocusable = value;
  540     if (!value && hasFocus) {
  541       unfocus(disposition: UnfocusDisposition.previouslyFocusedChild);
  542     }
  543     _manager?._markPropertiesChanged(this);
  544   }
  545 
  546   /// The context that was supplied to [attach].
  547   ///
  548   /// This is typically the context for the widget that is being focused, as it
  549   /// is used to determine the bounds of the widget.
  550   BuildContext get context => _context;
  551   BuildContext _context;
  552 
  553   /// Called if this focus node receives a key event while focused (i.e. when
  554   /// [hasFocus] returns true).
  555   ///
  556   /// {@macro flutter.widgets.focus_manager.focus.keyEvents}
  557   FocusOnKeyCallback get onKey => _onKey;
  558   FocusOnKeyCallback _onKey;
  559 
  560   FocusManager _manager;
  561   List<FocusNode> _ancestors;
  562   List<FocusNode> _descendants;
  563   bool _hasKeyboardToken = false;
  564 
  565   /// Returns the parent node for this object.
  566   ///
  567   /// All nodes except for the root [FocusScopeNode] ([FocusManager.rootScope])
  568   /// will be given a parent when they are added to the focus tree, which is
  569   /// done using [FocusAttachment.reparent].
  570   FocusNode get parent => _parent;
  571   FocusNode _parent;
  572 
  573   /// An iterator over the children of this node.
  574   Iterable<FocusNode> get children => _children;
  575   final List<FocusNode> _children = <FocusNode>[];
  576 
  577   /// An iterator over the children that are allowed to be traversed by the
  578   /// [FocusTraversalPolicy].
  579   Iterable<FocusNode> get traversalChildren {
  580     if (!canRequestFocus) {
  581       return const <FocusNode>[];
  582     }
  583     return children.where(
  584       (FocusNode node) => !node.skipTraversal && node.canRequestFocus,
  585     );
  586   }
  587 
  588   /// A debug label that is used for diagnostic output.
  589   ///
  590   /// Will always return null in release builds.
  591   String get debugLabel => _debugLabel;
  592   String _debugLabel;
  593   set debugLabel(String value) {
  594     assert(() {
  595       // Only set the value in debug builds.
  596       _debugLabel = value;
  597       return true;
  598     }());
  599   }
  600 
  601   FocusAttachment _attachment;
  602 
  603   /// An [Iterable] over the hierarchy of children below this one, in
  604   /// depth-first order.
  605   Iterable<FocusNode> get descendants {
  606     if (_descendants == null) {
  607       final List<FocusNode> result = <FocusNode>[];
  608       for (final FocusNode child in _children) {
  609         result.addAll(child.descendants);
  610         result.add(child);
  611       }
  612       _descendants = result;
  613     }
  614     return _descendants;
  615   }
  616 
  617   /// Returns all descendants which do not have the [skipTraversal] and do have
  618   /// the [canRequestFocus] flag set.
  619   Iterable<FocusNode> get traversalDescendants => descendants.where((FocusNode node) => !node.skipTraversal && node.canRequestFocus);
  620 
  621   /// An [Iterable] over the ancestors of this node.
  622   ///
  623   /// Iterates the ancestors of this node starting at the parent and iterating
  624   /// over successively more remote ancestors of this node, ending at the root
  625   /// [FocusScopeNode] ([FocusManager.rootScope]).
  626   Iterable<FocusNode> get ancestors {
  627     if (_ancestors == null) {
  628       final List<FocusNode> result = <FocusNode>[];
  629       FocusNode parent = _parent;
  630       while (parent != null) {
  631         result.add(parent);
  632         parent = parent._parent;
  633       }
  634       _ancestors = result;
  635     }
  636     return _ancestors;
  637   }
  638 
  639   /// Whether this node has input focus.
  640   ///
  641   /// A [FocusNode] has focus when it is an ancestor of a node that returns true
  642   /// from [hasPrimaryFocus], or it has the primary focus itself.
  643   ///
  644   /// The [hasFocus] accessor is different from [hasPrimaryFocus] in that
  645   /// [hasFocus] is true if the node is anywhere in the focus chain, but for
  646   /// [hasPrimaryFocus] the node must to be at the end of the chain to return
  647   /// true.
  648   ///
  649   /// A node that returns true for [hasFocus] will receive key events if none of
  650   /// its focused descendants returned true from their [onKey] handler.
  651   ///
  652   /// This object is a [ChangeNotifier], and notifies its [Listenable] listeners
  653   /// (registered via [addListener]) whenever this value changes.
  654   ///
  655   /// See also:
  656   ///
  657   ///  * [Focus.isAt], which is a static method that will return the focus
  658   ///    state of the nearest ancestor [Focus] widget's focus node.
  659   bool get hasFocus => hasPrimaryFocus || (_manager?.primaryFocus?.ancestors?.contains(this) ?? false);
  660 
  661   /// Returns true if this node currently has the application-wide input focus.
  662   ///
  663   /// A [FocusNode] has the primary focus when the node is focused in its
  664   /// nearest ancestor [FocusScopeNode] and [hasFocus] is true for all its
  665   /// ancestor nodes, but none of its descendants.
  666   ///
  667   /// This is different from [hasFocus] in that [hasFocus] is true if the node
  668   /// is anywhere in the focus chain, but here the node has to be at the end of
  669   /// the chain to return true.
  670   ///
  671   /// A node that returns true for [hasPrimaryFocus] will be the first node to
  672   /// receive key events through its [onKey] handler.
  673   ///
  674   /// This object notifies its listeners whenever this value changes.
  675   bool get hasPrimaryFocus => _manager?.primaryFocus == this;
  676 
  677   /// Returns the [FocusHighlightMode] that is currently in effect for this node.
  678   FocusHighlightMode get highlightMode => FocusManager.instance.highlightMode;
  679 
  680   /// Returns the nearest enclosing scope node above this node, including
  681   /// this node, if it's a scope.
  682   ///
  683   /// Returns null if no scope is found.
  684   ///
  685   /// Use [enclosingScope] to look for scopes above this node.
  686   FocusScopeNode get nearestScope => enclosingScope;
  687 
  688   /// Returns the nearest enclosing scope node above this node, or null if the
  689   /// node has not yet be added to the focus tree.
  690   ///
  691   /// If this node is itself a scope, this will only return ancestors of this
  692   /// scope.
  693   ///
  694   /// Use [nearestScope] to start at this node instead of above it.
  695   FocusScopeNode get enclosingScope {
  696     return ancestors.firstWhere((FocusNode node) => node is FocusScopeNode, orElse: () => null) as FocusScopeNode;
  697   }
  698 
  699   /// Returns the size of the attached widget's [RenderObject], in logical
  700   /// units.
  701   ///
  702   /// Size is the size of the transformed widget in global coordinates.
  703   Size get size => rect.size;
  704 
  705   /// Returns the global offset to the upper left corner of the attached
  706   /// widget's [RenderObject], in logical units.
  707   ///
  708   /// Offset is the offset of the transformed widget in global coordinates.
  709   Offset get offset {
  710     assert(
  711         context != null,
  712         "Tried to get the offset of a focus node that didn't have its context set yet.\n"
  713         'The context needs to be set before trying to evaluate traversal policies. '
  714         'Setting the context is typically done with the attach method.');
  715     final RenderObject object = context.findRenderObject();
  716     return MatrixUtils.transformPoint(object.getTransformTo(null), object.semanticBounds.topLeft);
  717   }
  718 
  719   /// Returns the global rectangle of the attached widget's [RenderObject], in
  720   /// logical units.
  721   ///
  722   /// Rect is the rectangle of the transformed widget in global coordinates.
  723   Rect get rect {
  724     assert(
  725         context != null,
  726         "Tried to get the bounds of a focus node that didn't have its context set yet.\n"
  727         'The context needs to be set before trying to evaluate traversal policies. '
  728         'Setting the context is typically done with the attach method.');
  729     final RenderObject object = context.findRenderObject();
  730     final Offset topLeft = MatrixUtils.transformPoint(object.getTransformTo(null), object.semanticBounds.topLeft);
  731     final Offset bottomRight = MatrixUtils.transformPoint(object.getTransformTo(null), object.semanticBounds.bottomRight);
  732     return Rect.fromLTRB(topLeft.dx, topLeft.dy, bottomRight.dx, bottomRight.dy);
  733   }
  734 
  735   /// Removes the focus on this node by moving the primary focus to another node.
  736   ///
  737   /// This method removes focus from a node that has the primary focus, cancels
  738   /// any outstanding requests to focus it, while setting the primary focus to
  739   /// another node according to the `disposition`.
  740   ///
  741   /// It is safe to call regardless of whether this node has ever requested
  742   /// focus or not. If this node doesn't have focus or primary focus, nothing
  743   /// happens.
  744   ///
  745   /// The `disposition` argument determines which node will receive primary
  746   /// focus after this one loses it.
  747   ///
  748   /// If `disposition` is set to [UnfocusDisposition.scope] (the default), then
  749   /// the previously focused node history of the enclosing scope will be
  750   /// cleared, and the primary focus will be moved to the nearest enclosing
  751   /// scope ancestor that is enabled for focus, ignoring the
  752   /// [FocusScopeNode.focusedChild] for that scope.
  753   ///
  754   /// If `disposition` is set to [UnfocusDisposition.previouslyFocusedChild],
  755   /// then this node will be removed from the previously focused list in the
  756   /// [enclosingScope], and the focus will be moved to the previously focused
  757   /// node of the [enclosingScope], which (if it is a scope itself), will find
  758   /// its focused child, etc., until a leaf focus node is found. If there is no
  759   /// previously focused child, then the scope itself will receive focus, as if
  760   /// [UnfocusDisposition.scope] were specified.
  761   ///
  762   /// If you want this node to lose focus and the focus to move to the next or
  763   /// previous node in the enclosing [FocusTraversalGroup], call [nextFocus] or
  764   /// [previousFocus] instead of calling `unfocus`.
  765   ///
  766   /// {@tool dartpad --template=stateful_widget_material}
  767   /// This example shows the difference between the different [UnfocusDisposition]
  768   /// values for [unfocus].
  769   ///
  770   /// Try setting focus on the four text fields by selecting them, and then
  771   /// select "UNFOCUS" to see what happens when the current
  772   /// [FocusManager.primaryFocus] is unfocused.
  773   ///
  774   /// Try pressing the TAB key after unfocusing to see what the next widget
  775   /// chosen is.
  776   ///
  777   /// ```dart imports
  778   /// import 'package:flutter/foundation.dart';
  779   /// ```
  780   ///
  781   /// ```dart
  782   /// UnfocusDisposition disposition = UnfocusDisposition.scope;
  783   ///
  784   /// @override
  785   /// Widget build(BuildContext context) {
  786   ///   return Material(
  787   ///     child: Container(
  788   ///       color: Colors.white,
  789   ///       child: Column(
  790   ///         mainAxisAlignment: MainAxisAlignment.center,
  791   ///         children: <Widget>[
  792   ///           Wrap(
  793   ///             children: List<Widget>.generate(4, (int index) {
  794   ///               return SizedBox(
  795   ///                 width: 200,
  796   ///                 child: Padding(
  797   ///                   padding: const EdgeInsets.all(8.0),
  798   ///                   child: TextField(
  799   ///                     decoration: InputDecoration(border: OutlineInputBorder()),
  800   ///                   ),
  801   ///                 ),
  802   ///               );
  803   ///             }),
  804   ///           ),
  805   ///           Row(
  806   ///             mainAxisAlignment: MainAxisAlignment.spaceAround,
  807   ///             children: <Widget>[
  808   ///               ...List<Widget>.generate(UnfocusDisposition.values.length,
  809   ///                   (int index) {
  810   ///                 return Row(
  811   ///                   mainAxisSize: MainAxisSize.min,
  812   ///                   children: <Widget>[
  813   ///                     Radio<UnfocusDisposition>(
  814   ///                       groupValue: disposition,
  815   ///                       onChanged: (UnfocusDisposition value) {
  816   ///                         setState(() {
  817   ///                           disposition = value;
  818   ///                         });
  819   ///                       },
  820   ///                       value: UnfocusDisposition.values[index],
  821   ///                     ),
  822   ///                     Text(describeEnum(UnfocusDisposition.values[index])),
  823   ///                   ],
  824   ///                 );
  825   ///               }),
  826   ///               OutlinedButton(
  827   ///                 child: const Text('UNFOCUS'),
  828   ///                 onPressed: () {
  829   ///                   setState(() {
  830   ///                     primaryFocus.unfocus(disposition: disposition);
  831   ///                   });
  832   ///                 },
  833   ///               ),
  834   ///             ],
  835   ///           ),
  836   ///         ],
  837   ///       ),
  838   ///     ),
  839   ///   );
  840   /// }
  841   /// ```
  842   /// {@end-tool}
  843   void unfocus({
  844     UnfocusDisposition disposition = UnfocusDisposition.scope,
  845   }) {
  846     assert(disposition != null);
  847     if (!hasFocus && (_manager == null || _manager._markedForFocus != this)) {
  848       return;
  849     }
  850     FocusScopeNode scope = enclosingScope;
  851     if (scope == null) {
  852       // If the scope is null, then this is either the root node, or a node that
  853       // is not yet in the tree, neither of which do anything when unfocused.
  854       return;
  855     }
  856     switch (disposition) {
  857       case UnfocusDisposition.scope:
  858         // If it can't request focus, then don't modify its focused children.
  859         if (scope.canRequestFocus) {
  860           // Clearing the focused children here prevents re-focusing the node
  861           // that we just unfocused if we immediately hit "next" after
  862           // unfocusing, and also prevents choosing to refocus the next-to-last
  863           // focused child if unfocus is called more than once.
  864           scope._focusedChildren.clear();
  865         }
  866 
  867         while (!scope.canRequestFocus) {
  868           scope = scope.enclosingScope ?? _manager?.rootScope;
  869         }
  870         scope?._doRequestFocus(findFirstFocus: false);
  871         break;
  872       case UnfocusDisposition.previouslyFocusedChild:
  873         // Select the most recent focused child from the nearest focusable scope
  874         // and focus that. If there isn't one, focus the scope itself.
  875         if (scope.canRequestFocus) {
  876           scope?._focusedChildren?.remove(this);
  877         }
  878         while (!scope.canRequestFocus) {
  879           scope.enclosingScope?._focusedChildren?.remove(scope);
  880           scope = scope.enclosingScope ?? _manager?.rootScope;
  881         }
  882         scope?._doRequestFocus(findFirstFocus: true);
  883         break;
  884     }
  885     assert(_focusDebug('Unfocused node:', <String>['primary focus was $this', 'next focus will be ${_manager?._markedForFocus}']));
  886   }
  887 
  888   /// Removes the keyboard token from this focus node if it has one.
  889   ///
  890   /// This mechanism helps distinguish between an input control gaining focus by
  891   /// default and gaining focus as a result of an explicit user action.
  892   ///
  893   /// When a focus node requests the focus (either via
  894   /// [FocusScopeNode.requestFocus] or [FocusScopeNode.autofocus]), the focus
  895   /// node receives a keyboard token if it does not already have one. Later,
  896   /// when the focus node becomes focused, the widget that manages the
  897   /// [TextInputConnection] should show the keyboard (i.e. call
  898   /// [TextInputConnection.show]) only if it successfully consumes the keyboard
  899   /// token from the focus node.
  900   ///
  901   /// Returns true if this method successfully consumes the keyboard token.
  902   bool consumeKeyboardToken() {
  903     if (!_hasKeyboardToken) {
  904       return false;
  905     }
  906     _hasKeyboardToken = false;
  907     return true;
  908   }
  909 
  910   // Marks the node as being the next to be focused, meaning that it will become
  911   // the primary focus and notify listeners of a focus change the next time
  912   // focus is resolved by the manager. If something else calls _markNextFocus
  913   // before then, then that node will become the next focus instead of the
  914   // previous one.
  915   void _markNextFocus(FocusNode newFocus) {
  916     if (_manager != null) {
  917       // If we have a manager, then let it handle the focus change.
  918       _manager._markNextFocus(this);
  919       return;
  920     }
  921     // If we don't have a manager, then change the focus locally.
  922     newFocus?._setAsFocusedChildForScope();
  923     newFocus?._notify();
  924     if (newFocus != this) {
  925       _notify();
  926     }
  927   }
  928 
  929   // Removes the given FocusNode and its children as a child of this node.
  930   @mustCallSuper
  931   void _removeChild(FocusNode node, {bool removeScopeFocus = true}) {
  932     assert(node != null);
  933     assert(_children.contains(node), "Tried to remove a node that wasn't a child.");
  934     assert(node._parent == this);
  935     assert(node._manager == _manager);
  936 
  937     if (removeScopeFocus) {
  938       node.enclosingScope?._focusedChildren?.remove(node);
  939     }
  940 
  941     node._parent = null;
  942     _children.remove(node);
  943     for (final FocusNode ancestor in ancestors) {
  944       ancestor._descendants = null;
  945     }
  946     _descendants = null;
  947     assert(_manager == null || !_manager.rootScope.descendants.contains(node));
  948   }
  949 
  950   void _updateManager(FocusManager manager) {
  951     _manager = manager;
  952     for (final FocusNode descendant in descendants) {
  953       descendant._manager = manager;
  954       descendant._ancestors = null;
  955     }
  956   }
  957 
  958   // Used by FocusAttachment.reparent to perform the actual parenting operation.
  959   @mustCallSuper
  960   void _reparent(FocusNode child) {
  961     assert(child != null);
  962     assert(child != this, 'Tried to make a child into a parent of itself.');
  963     if (child._parent == this) {
  964       assert(_children.contains(child), "Found a node that says it's a child, but doesn't appear in the child list.");
  965       // The child is already a child of this parent.
  966       return;
  967     }
  968     assert(_manager == null || child != _manager.rootScope, "Reparenting the root node isn't allowed.");
  969     assert(!ancestors.contains(child), 'The supplied child is already an ancestor of this node. Loops are not allowed.');
  970     final FocusScopeNode oldScope = child.enclosingScope;
  971     final bool hadFocus = child.hasFocus;
  972     child._parent?._removeChild(child, removeScopeFocus: oldScope != nearestScope);
  973     _children.add(child);
  974     child._parent = this;
  975     child._ancestors = null;
  976     child._updateManager(_manager);
  977     for (final FocusNode ancestor in child.ancestors) {
  978       ancestor._descendants = null;
  979     }
  980     if (hadFocus) {
  981       // Update the focus chain for the current focus without changing it.
  982       _manager?.primaryFocus?._setAsFocusedChildForScope();
  983     }
  984     if (oldScope != null && child.context != null && child.enclosingScope != oldScope) {
  985       FocusTraversalGroup.of(child.context, nullOk: true)?.changedScope(node: child, oldScope: oldScope);
  986     }
  987     if (child._requestFocusWhenReparented) {
  988       child._doRequestFocus(findFirstFocus: true);
  989       child._requestFocusWhenReparented = false;
  990     }
  991   }
  992 
  993   /// Called by the _host_ [StatefulWidget] to attach a [FocusNode] to the
  994   /// widget tree.
  995   ///
  996   /// In order to attach a [FocusNode] to the widget tree, call [attach],
  997   /// typically from the [StatefulWidget]'s [State.initState] method.
  998   ///
  999   /// If the focus node in the host widget is swapped out, the new node will
 1000   /// need to be attached. [FocusAttachment.detach] should be called on the old
 1001   /// node, and then [attach] called on the new node. This typically happens in
 1002   /// the [State.didUpdateWidget] method.
 1003   @mustCallSuper
 1004   FocusAttachment attach(BuildContext context, {FocusOnKeyCallback onKey}) {
 1005     _context = context;
 1006     _onKey = onKey ?? _onKey;
 1007     _attachment = FocusAttachment._(this);
 1008     return _attachment;
 1009   }
 1010 
 1011   @override
 1012   void dispose() {
 1013     // Detaching will also unfocus and clean up the manager's data structures.
 1014     _attachment?.detach();
 1015     super.dispose();
 1016   }
 1017 
 1018   @mustCallSuper
 1019   void _notify() {
 1020     if (_parent == null) {
 1021       // no longer part of the tree, so don't notify.
 1022       return;
 1023     }
 1024     if (hasPrimaryFocus) {
 1025       _setAsFocusedChildForScope();
 1026     }
 1027     notifyListeners();
 1028   }
 1029 
 1030   /// Requests the primary focus for this node, or for a supplied [node], which
 1031   /// will also give focus to its [ancestors].
 1032   ///
 1033   /// If called without a node, request focus for this node. If the node hasn't
 1034   /// been added to the focus tree yet, then defer the focus request until it
 1035   /// is, allowing newly created widgets to request focus as soon as they are
 1036   /// added.
 1037   ///
 1038   /// If the given [node] is not yet a part of the focus tree, then this method
 1039   /// will add the [node] as a child of this node before requesting focus.
 1040   ///
 1041   /// If the given [node] is a [FocusScopeNode] and that focus scope node has a
 1042   /// non-null [FocusScopeNode.focusedChild], then request the focus for the
 1043   /// focused child. This process is recursive and continues until it encounters
 1044   /// either a focus scope node with a null focused child or an ordinary
 1045   /// (non-scope) [FocusNode] is found.
 1046   ///
 1047   /// The node is notified that it has received the primary focus in a
 1048   /// microtask, so notification may lag the request by up to one frame.
 1049   void requestFocus([FocusNode node]) {
 1050     if (node != null) {
 1051       if (node._parent == null) {
 1052         _reparent(node);
 1053       }
 1054       assert(node.ancestors.contains(this), 'Focus was requested for a node that is not a descendant of the scope from which it was requested.');
 1055       node._doRequestFocus(findFirstFocus: true);
 1056       return;
 1057     }
 1058     _doRequestFocus(findFirstFocus: true);
 1059   }
 1060 
 1061   // Note that this is overridden in FocusScopeNode.
 1062   void _doRequestFocus({@required bool findFirstFocus}) {
 1063     assert(findFirstFocus != null);
 1064     if (!canRequestFocus) {
 1065       assert(_focusDebug('Node NOT requesting focus because canRequestFocus is false: $this'));
 1066       return;
 1067     }
 1068     // If the node isn't part of the tree, then we just defer the focus request
 1069     // until the next time it is reparented, so that it's possible to focus
 1070     // newly added widgets.
 1071     if (_parent == null) {
 1072       _requestFocusWhenReparented = true;
 1073       return;
 1074     }
 1075     _setAsFocusedChildForScope();
 1076     if (hasPrimaryFocus && (_manager._markedForFocus == null || _manager._markedForFocus == this)) {
 1077       return;
 1078     }
 1079     _hasKeyboardToken = true;
 1080     assert(_focusDebug('Node requesting focus: $this'));
 1081     _markNextFocus(this);
 1082   }
 1083 
 1084   // If set to true, the node will request focus on this node the next time
 1085   // this node is reparented in the focus tree.
 1086   //
 1087   // Once requestFocus has been called at the next reparenting, this value
 1088   // will be reset to false.
 1089   //
 1090   // This will only force a call to requestFocus for the node once the next time
 1091   // the node is reparented. After that, _requestFocusWhenReparented would need
 1092   // to be set to true again to have it be focused again on the next
 1093   // reparenting.
 1094   //
 1095   // This is used when requestFocus is called and there is no parent yet.
 1096   bool _requestFocusWhenReparented = false;
 1097 
 1098   /// Sets this node as the [FocusScopeNode.focusedChild] of the enclosing
 1099   /// scope.
 1100   ///
 1101   /// Sets this node as the focused child for the enclosing scope, and that
 1102   /// scope as the focused child for the scope above it, etc., until it reaches
 1103   /// the root node. It doesn't change the primary focus, it just changes what
 1104   /// node would be focused if the enclosing scope receives focus, and keeps
 1105   /// track of previously focused children in that scope, so that if the focused
 1106   /// child in that scope is removed, the previous focus returns.
 1107   void _setAsFocusedChildForScope() {
 1108     FocusNode scopeFocus = this;
 1109     for (final FocusScopeNode ancestor in ancestors.whereType<FocusScopeNode>()) {
 1110       assert(scopeFocus != ancestor, 'Somehow made a loop by setting focusedChild to its scope.');
 1111       assert(_focusDebug('Setting $scopeFocus as focused child for scope:', <String>[ancestor.toString()]));
 1112       // Remove it anywhere in the focused child history.
 1113       ancestor._focusedChildren.remove(scopeFocus);
 1114       // Add it to the end of the list, which is also the top of the queue: The
 1115       // end of the list represents the currently focused child.
 1116       ancestor._focusedChildren.add(scopeFocus);
 1117       scopeFocus = ancestor;
 1118     }
 1119   }
 1120 
 1121   /// Request to move the focus to the next focus node, by calling the
 1122   /// [FocusTraversalPolicy.next] method.
 1123   ///
 1124   /// Returns true if it successfully found a node and requested focus.
 1125   bool nextFocus() => FocusTraversalGroup.of(context).next(this);
 1126 
 1127   /// Request to move the focus to the previous focus node, by calling the
 1128   /// [FocusTraversalPolicy.previous] method.
 1129   ///
 1130   /// Returns true if it successfully found a node and requested focus.
 1131   bool previousFocus() => FocusTraversalGroup.of(context).previous(this);
 1132 
 1133   /// Request to move the focus to the nearest focus node in the given
 1134   /// direction, by calling the [FocusTraversalPolicy.inDirection] method.
 1135   ///
 1136   /// Returns true if it successfully found a node and requested focus.
 1137   bool focusInDirection(TraversalDirection direction) => FocusTraversalGroup.of(context).inDirection(this, direction);
 1138 
 1139   @override
 1140   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
 1141     super.debugFillProperties(properties);
 1142     properties.add(DiagnosticsProperty<BuildContext>('context', context, defaultValue: null));
 1143     properties.add(FlagProperty('descendantsAreFocusable', value: descendantsAreFocusable, ifFalse: 'DESCENDANTS UNFOCUSABLE', defaultValue: true));
 1144     properties.add(FlagProperty('canRequestFocus', value: canRequestFocus, ifFalse: 'NOT FOCUSABLE', defaultValue: true));
 1145     properties.add(FlagProperty('hasFocus', value: hasFocus && !hasPrimaryFocus, ifTrue: 'IN FOCUS PATH', defaultValue: false));
 1146     properties.add(FlagProperty('hasPrimaryFocus', value: hasPrimaryFocus, ifTrue: 'PRIMARY FOCUS', defaultValue: false));
 1147   }
 1148 
 1149   @override
 1150   List<DiagnosticsNode> debugDescribeChildren() {
 1151     int count = 1;
 1152     return _children.map<DiagnosticsNode>((FocusNode child) {
 1153       return child.toDiagnosticsNode(name: 'Child ${count++}');
 1154     }).toList();
 1155   }
 1156 
 1157   @override
 1158   String toStringShort() {
 1159     final bool hasDebugLabel = debugLabel != null && debugLabel.isNotEmpty;
 1160     final String extraData = '${hasDebugLabel ? debugLabel : ''}'
 1161         '${hasFocus && hasDebugLabel ? ' ' : ''}'
 1162         '${hasFocus && !hasPrimaryFocus ? '[IN FOCUS PATH]' : ''}'
 1163         '${hasPrimaryFocus ? '[PRIMARY FOCUS]' : ''}';
 1164     return '${describeIdentity(this)}${extraData.isNotEmpty ? '($extraData)' : ''}';
 1165   }
 1166 }
 1167 
 1168 /// A subclass of [FocusNode] that acts as a scope for its descendants,
 1169 /// maintaining information about which descendant is currently or was last
 1170 /// focused.
 1171 ///
 1172 /// _Please see the [FocusScope] and [Focus] widgets, which are utility widgets
 1173 /// that manage their own [FocusScopeNode]s and [FocusNode]s, respectively. If
 1174 /// they aren't appropriate, [FocusScopeNode]s can be managed directly._
 1175 ///
 1176 /// [FocusScopeNode] organizes [FocusNode]s into _scopes_. Scopes form sub-trees
 1177 /// of nodes that can be traversed as a group. Within a scope, the most recent
 1178 /// nodes to have focus are remembered, and if a node is focused and then
 1179 /// removed, the original node receives focus again.
 1180 ///
 1181 /// From a [FocusScopeNode], calling [setFirstFocus], sets the given focus scope
 1182 /// as the [focusedChild] of this node, adopting if it isn't already part of the
 1183 /// focus tree.
 1184 ///
 1185 /// {@macro flutter.widgets.focus_manager.focus.lifecycle}
 1186 /// {@macro flutter.widgets.focus_manager.focus.keyEvents}
 1187 ///
 1188 /// See also:
 1189 ///
 1190 ///  * [Focus], a widget that manages a [FocusNode] and provides access to focus
 1191 ///    information and actions to its descendant widgets.
 1192 ///  * [FocusManager], a singleton that manages the primary focus and
 1193 ///    distributes key events to focused nodes.
 1194 class FocusScopeNode extends FocusNode {
 1195   /// Creates a [FocusScopeNode].
 1196   ///
 1197   /// All parameters are optional.
 1198   FocusScopeNode({
 1199     String debugLabel,
 1200     FocusOnKeyCallback onKey,
 1201     bool skipTraversal = false,
 1202     bool canRequestFocus = true,
 1203   })  : assert(skipTraversal != null),
 1204         assert(canRequestFocus != null),
 1205         super(
 1206           debugLabel: debugLabel,
 1207           onKey: onKey,
 1208           canRequestFocus: canRequestFocus,
 1209           descendantsAreFocusable: true,
 1210           skipTraversal: skipTraversal,
 1211         );
 1212 
 1213   @override
 1214   FocusScopeNode get nearestScope => this;
 1215 
 1216   /// Returns true if this scope is the focused child of its parent scope.
 1217   bool get isFirstFocus => enclosingScope.focusedChild == this;
 1218 
 1219   /// Returns the child of this node that should receive focus if this scope
 1220   /// node receives focus.
 1221   ///
 1222   /// If [hasFocus] is true, then this points to the child of this node that is
 1223   /// currently focused.
 1224   ///
 1225   /// Returns null if there is no currently focused child.
 1226   FocusNode get focusedChild {
 1227     assert(_focusedChildren.isEmpty || _focusedChildren.last.enclosingScope == this, 'Focused child does not have the same idea of its enclosing scope as the scope does.');
 1228     return _focusedChildren.isNotEmpty ? _focusedChildren.last : null;
 1229   }
 1230 
 1231   // A stack of the children that have been set as the focusedChild, most recent
 1232   // last (which is the top of the stack).
 1233   final List<FocusNode> _focusedChildren = <FocusNode>[];
 1234 
 1235   /// Make the given [scope] the active child scope for this scope.
 1236   ///
 1237   /// If the given [scope] is not yet a part of the focus tree, then add it to
 1238   /// the tree as a child of this scope. If it is already part of the focus
 1239   /// tree, the given scope must be a descendant of this scope.
 1240   void setFirstFocus(FocusScopeNode scope) {
 1241     assert(scope != null);
 1242     assert(scope != this, 'Unexpected self-reference in setFirstFocus.');
 1243     assert(_focusDebug('Setting scope as first focus in $this to node:', <String>[scope.toString()]));
 1244     if (scope._parent == null) {
 1245       _reparent(scope);
 1246     }
 1247     assert(scope.ancestors.contains(this), '$FocusScopeNode $scope must be a child of $this to set it as first focus.');
 1248     if (hasFocus) {
 1249       scope._doRequestFocus(findFirstFocus: true);
 1250     } else {
 1251       scope._setAsFocusedChildForScope();
 1252     }
 1253   }
 1254 
 1255   /// If this scope lacks a focus, request that the given node become the focus.
 1256   ///
 1257   /// If the given node is not yet part of the focus tree, then add it as a
 1258   /// child of this node.
 1259   ///
 1260   /// Useful for widgets that wish to grab the focus if no other widget already
 1261   /// has the focus.
 1262   ///
 1263   /// The node is notified that it has received the primary focus in a
 1264   /// microtask, so notification may lag the request by up to one frame.
 1265   void autofocus(FocusNode node) {
 1266     assert(_focusDebug('Node autofocusing: $node'));
 1267     if (focusedChild == null) {
 1268       if (node._parent == null) {
 1269         _reparent(node);
 1270       }
 1271       assert(node.ancestors.contains(this), 'Autofocus was requested for a node that is not a descendant of the scope from which it was requested.');
 1272       node._doRequestFocus(findFirstFocus: true);
 1273     }
 1274   }
 1275 
 1276   @override
 1277   void _doRequestFocus({@required bool findFirstFocus}) {
 1278     assert(findFirstFocus != null);
 1279 
 1280     // It is possible that a previously focused child is no longer focusable.
 1281     while (focusedChild != null && !focusedChild.canRequestFocus)
 1282       _focusedChildren.removeLast();
 1283 
 1284     // If findFirstFocus is false, then the request is to make this scope the
 1285     // focus instead of looking for the ultimate first focus for this scope and
 1286     // its descendants.
 1287     if (!findFirstFocus) {
 1288       if (canRequestFocus) {
 1289         _setAsFocusedChildForScope();
 1290         _markNextFocus(this);
 1291       }
 1292       return;
 1293     }
 1294 
 1295     // Start with the primary focus as the focused child of this scope, if there
 1296     // is one. Otherwise start with this node itself.
 1297     FocusNode primaryFocus = focusedChild ?? this;
 1298     // Keep going down through scopes until the ultimately focusable item is
 1299     // found, a scope doesn't have a focusedChild, or a non-scope is
 1300     // encountered.
 1301     while (primaryFocus is FocusScopeNode && primaryFocus.focusedChild != null) {
 1302       final FocusScopeNode scope = primaryFocus as FocusScopeNode;
 1303       primaryFocus = scope.focusedChild;
 1304     }
 1305     if (identical(primaryFocus, this)) {
 1306       // We didn't find a FocusNode at the leaf, so we're focusing the scope, if
 1307       // allowed.
 1308       if (primaryFocus.canRequestFocus) {
 1309         _setAsFocusedChildForScope();
 1310         _markNextFocus(this);
 1311       }
 1312     } else {
 1313       // We found a FocusScopeNode at the leaf, so ask it to focus itself
 1314       // instead of this scope. That will cause this scope to return true from
 1315       // hasFocus, but false from hasPrimaryFocus.
 1316       primaryFocus._doRequestFocus(findFirstFocus: findFirstFocus);
 1317     }
 1318   }
 1319 
 1320   @override
 1321   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
 1322     super.debugFillProperties(properties);
 1323     if (_focusedChildren.isEmpty) {
 1324       return;
 1325     }
 1326     final List<String> childList = _focusedChildren.reversed.map<String>((FocusNode child) {
 1327       return child.toStringShort();
 1328     }).toList();
 1329     properties.add(IterableProperty<String>('focusedChildren', childList, defaultValue: <String>[]));
 1330   }
 1331 }
 1332 
 1333 /// An enum to describe which kind of focus highlight behavior to use when
 1334 /// displaying focus information.
 1335 enum FocusHighlightMode {
 1336   /// Touch interfaces will not show the focus highlight except for controls
 1337   /// which bring up the soft keyboard.
 1338   ///
 1339   /// If a device that uses a traditional mouse and keyboard has a touch screen
 1340   /// attached, it can also enter `touch` mode if the user is using the touch
 1341   /// screen.
 1342   touch,
 1343 
 1344   /// Traditional interfaces (keyboard and mouse) will show the currently
 1345   /// focused control via a focus highlight of some sort.
 1346   ///
 1347   /// If a touch device (like a mobile phone) has a keyboard and/or mouse
 1348   /// attached, it also can enter `traditional` mode if the user is using these
 1349   /// input devices.
 1350   traditional,
 1351 }
 1352 
 1353 /// An enum to describe how the current value of [FocusManager.highlightMode] is
 1354 /// determined. The strategy is set on [FocusManager.highlightStrategy].
 1355 enum FocusHighlightStrategy {
 1356   /// Automatic switches between the various highlight modes based on the last
 1357   /// kind of input that was received. This is the default.
 1358   automatic,
 1359 
 1360   /// [FocusManager.highlightMode] always returns [FocusHighlightMode.touch].
 1361   alwaysTouch,
 1362 
 1363   /// [FocusManager.highlightMode] always returns [FocusHighlightMode.traditional].
 1364   alwaysTraditional,
 1365 }
 1366 
 1367 /// Manages the focus tree.
 1368 ///
 1369 /// The focus tree is a separate, sparser, tree from the widget tree that
 1370 /// maintains the hierarchical relationship between focusable widgets in the
 1371 /// widget tree.
 1372 ///
 1373 /// The focus manager is responsible for tracking which [FocusNode] has the
 1374 /// primary input focus (the [primaryFocus]), holding the [FocusScopeNode] that
 1375 /// is the root of the focus tree (the [rootScope]), and what the current
 1376 /// [highlightMode] is. It also distributes key events from [RawKeyboard] to the
 1377 /// nodes in the focus tree.
 1378 ///
 1379 /// The singleton [FocusManager] instance is held by the [WidgetsBinding] as
 1380 /// [WidgetsBinding.focusManager], and can be conveniently accessed using the
 1381 /// [FocusManager.instance] static accessor.
 1382 ///
 1383 /// To find the [FocusNode] for a given [BuildContext], use [Focus.of]. To find
 1384 /// the [FocusScopeNode] for a given [BuildContext], use [FocusScope.of].
 1385 ///
 1386 /// If you would like notification whenever the [primaryFocus] changes, register
 1387 /// a listener with [addListener]. When you no longer want to receive these
 1388 /// events, as when your object is about to be disposed, you must unregister
 1389 /// with [removeListener] to avoid memory leaks. Removing listeners is typically
 1390 /// done in [State.dispose] on stateful widgets.
 1391 ///
 1392 /// The [highlightMode] describes how focus highlights should be displayed on
 1393 /// components in the UI. The [highlightMode] changes are notified separately
 1394 /// via [addHighlightModeListener] and removed with
 1395 /// [removeHighlightModeListener]. The highlight mode changes when the user
 1396 /// switches from a mouse to a touch interface, or vice versa.
 1397 ///
 1398 /// The widgets that are used to manage focus in the widget tree are:
 1399 ///
 1400 ///  * [Focus], a widget that manages a [FocusNode] in the focus tree so that
 1401 ///    the focus tree reflects changes in the widget hierarchy.
 1402 ///  * [FocusScope], a widget that manages a [FocusScopeNode] in the focus tree,
 1403 ///    creating a new scope for restricting focus to a set of focus nodes.
 1404 ///  * [FocusTraversalGroup], a widget that groups together nodes that should be
 1405 ///    traversed using an order described by a given [FocusTraversalPolicy].
 1406 ///
 1407 /// See also:
 1408 ///
 1409 ///  * [FocusNode], which is a node in the focus tree that can receive focus.
 1410 ///  * [FocusScopeNode], which is a node in the focus tree used to collect
 1411 ///    subtrees into groups and restrict focus to them.
 1412 ///  * The [primaryFocus] global accessor, for convenient access from anywhere
 1413 ///    to the current focus manager state.
 1414 class FocusManager with DiagnosticableTreeMixin, ChangeNotifier {
 1415   /// Creates an object that manages the focus tree.
 1416   ///
 1417   /// This constructor is rarely called directly. To access the [FocusManager],
 1418   /// consider using the [FocusManager.instance] accessor instead (which gets it
 1419   /// from the [WidgetsBinding] singleton).
 1420   FocusManager() {
 1421     rootScope._manager = this;
 1422     RawKeyboard.instance.keyEventHandler = _handleRawKeyEvent;
 1423     GestureBinding.instance.pointerRouter.addGlobalRoute(_handlePointerEvent);
 1424   }
 1425 
 1426   /// Provides convenient access to the current [FocusManager] singleton from
 1427   /// the [WidgetsBinding] instance.
 1428   static FocusManager get instance => WidgetsBinding.instance.focusManager;
 1429 
 1430   /// Sets the strategy by which [highlightMode] is determined.
 1431   ///
 1432   /// If set to [FocusHighlightStrategy.automatic], then the highlight mode will
 1433   /// change depending upon the interaction mode used last. For instance, if the
 1434   /// last interaction was a touch interaction, then [highlightMode] will return
 1435   /// [FocusHighlightMode.touch], and focus highlights will only appear on
 1436   /// widgets that bring up a soft keyboard. If the last interaction was a
 1437   /// non-touch interaction (hardware keyboard press, mouse click, etc.), then
 1438   /// [highlightMode] will return [FocusHighlightMode.traditional], and focus
 1439   /// highlights will appear on all widgets.
 1440   ///
 1441   /// If set to [FocusHighlightStrategy.alwaysTouch] or
 1442   /// [FocusHighlightStrategy.alwaysTraditional], then [highlightMode] will
 1443   /// always return [FocusHighlightMode.touch] or
 1444   /// [FocusHighlightMode.traditional], respectively, regardless of the last UI
 1445   /// interaction type.
 1446   ///
 1447   /// The initial value of [highlightMode] depends upon the value of
 1448   /// [defaultTargetPlatform] and [BaseMouseTracker.mouseIsConnected] of
 1449   /// [RendererBinding.mouseTracker], making a guess about which interaction is
 1450   /// most appropriate for the initial interaction mode.
 1451   ///
 1452   /// Defaults to [FocusHighlightStrategy.automatic].
 1453   FocusHighlightStrategy get highlightStrategy => _highlightStrategy;
 1454   FocusHighlightStrategy _highlightStrategy = FocusHighlightStrategy.automatic;
 1455   set highlightStrategy(FocusHighlightStrategy highlightStrategy) {
 1456     _highlightStrategy = highlightStrategy;
 1457     _updateHighlightMode();
 1458   }
 1459 
 1460   static FocusHighlightMode get _defaultModeForPlatform {
 1461     // Assume that if we're on one of the mobile platforms, and there's no mouse
 1462     // connected, that the initial interaction will be touch-based, and that
 1463     // it's traditional mouse and keyboard on all other platforms.
 1464     //
 1465     // This only affects the initial value: the ongoing value is updated to a
 1466     // known correct value as soon as any pointer/keyboard events are received.
 1467     switch (defaultTargetPlatform) {
 1468       case TargetPlatform.android:
 1469       case TargetPlatform.fuchsia:
 1470       case TargetPlatform.iOS:
 1471         if (WidgetsBinding.instance.mouseTracker.mouseIsConnected) {
 1472           return FocusHighlightMode.traditional;
 1473         }
 1474         return FocusHighlightMode.touch;
 1475       case TargetPlatform.linux:
 1476       case TargetPlatform.macOS:
 1477       case TargetPlatform.windows:
 1478         return FocusHighlightMode.traditional;
 1479     }
 1480     assert(false, 'Unhandled target platform $defaultTargetPlatform');
 1481     return null;
 1482   }
 1483 
 1484   /// Indicates the current interaction mode for focus highlights.
 1485   ///
 1486   /// The value returned depends upon the [highlightStrategy] used, and possibly
 1487   /// (depending on the value of [highlightStrategy]) the most recent
 1488   /// interaction mode that they user used.
 1489   ///
 1490   /// If [highlightMode] returns [FocusHighlightMode.touch], then widgets should
 1491   /// not draw their focus highlight unless they perform text entry.
 1492   ///
 1493   /// If [highlightMode] returns [FocusHighlightMode.traditional], then widgets should
 1494   /// draw their focus highlight whenever they are focused.
 1495   // Don't want to set _highlightMode here, since it's possible for the target
 1496   // platform to change (especially in tests).
 1497   FocusHighlightMode get highlightMode => _highlightMode ?? _defaultModeForPlatform;
 1498   FocusHighlightMode _highlightMode;
 1499 
 1500   // If set, indicates if the last interaction detected was touch or not.
 1501   // If null, no interactions have occurred yet.
 1502   bool _lastInteractionWasTouch;
 1503 
 1504   // Update function to be called whenever the state relating to highlightMode
 1505   // changes.
 1506   void _updateHighlightMode() {
 1507     FocusHighlightMode newMode;
 1508     switch (highlightStrategy) {
 1509       case FocusHighlightStrategy.automatic:
 1510         if (_lastInteractionWasTouch == null) {
 1511           // If we don't have any information about the last interaction yet,
 1512           // then just rely on the default value for the platform, which will be
 1513           // determined based on the target platform if _highlightMode is not
 1514           // set.
 1515           return;
 1516         }
 1517         if (_lastInteractionWasTouch) {
 1518           newMode = FocusHighlightMode.touch;
 1519         } else {
 1520           newMode = FocusHighlightMode.traditional;
 1521         }
 1522         break;
 1523       case FocusHighlightStrategy.alwaysTouch:
 1524         newMode = FocusHighlightMode.touch;
 1525         break;
 1526       case FocusHighlightStrategy.alwaysTraditional:
 1527         newMode = FocusHighlightMode.traditional;
 1528         break;
 1529     }
 1530     // We can't just compare newMode with _highlightMode here, since
 1531     // _highlightMode could be null, so we want to compare with the return value
 1532     // for the getter, since that's what clients will be looking at.
 1533     final FocusHighlightMode oldMode = highlightMode;
 1534     _highlightMode = newMode;
 1535     if (highlightMode != oldMode) {
 1536       _notifyHighlightModeListeners();
 1537     }
 1538   }
 1539 
 1540   // The list of listeners for [highlightMode] state changes.
 1541   final HashedObserverList<ValueChanged<FocusHighlightMode>> _listeners = HashedObserverList<ValueChanged<FocusHighlightMode>>();
 1542 
 1543   /// Register a closure to be called when the [FocusManager] notifies its listeners
 1544   /// that the value of [highlightMode] has changed.
 1545   void addHighlightModeListener(ValueChanged<FocusHighlightMode> listener) => _listeners.add(listener);
 1546 
 1547   /// Remove a previously registered closure from the list of closures that the
 1548   /// [FocusManager] notifies.
 1549   void removeHighlightModeListener(ValueChanged<FocusHighlightMode> listener) => _listeners?.remove(listener);
 1550 
 1551   void _notifyHighlightModeListeners() {
 1552     if (_listeners.isEmpty) {
 1553       return;
 1554     }
 1555     final List<ValueChanged<FocusHighlightMode>> localListeners = List<ValueChanged<FocusHighlightMode>>.from(_listeners);
 1556     for (final ValueChanged<FocusHighlightMode> listener in localListeners) {
 1557       try {
 1558         if (_listeners.contains(listener)) {
 1559           listener(highlightMode);
 1560         }
 1561       } catch (exception, stack) {
 1562         InformationCollector collector;
 1563         assert(() {
 1564           collector = () sync* {
 1565             yield DiagnosticsProperty<FocusManager>(
 1566               'The $runtimeType sending notification was',
 1567               this,
 1568               style: DiagnosticsTreeStyle.errorProperty,
 1569             );
 1570           };
 1571           return true;
 1572         }());
 1573         FlutterError.reportError(FlutterErrorDetails(
 1574           exception: exception,
 1575           stack: stack,
 1576           library: 'widgets library',
 1577           context: ErrorDescription('while dispatching notifications for $runtimeType'),
 1578           informationCollector: collector,
 1579         ));
 1580       }
 1581     }
 1582   }
 1583 
 1584   /// The root [FocusScopeNode] in the focus tree.
 1585   ///
 1586   /// This field is rarely used directly. To find the nearest [FocusScopeNode]
 1587   /// for a given [FocusNode], call [FocusNode.nearestScope].
 1588   final FocusScopeNode rootScope = FocusScopeNode(debugLabel: 'Root Focus Scope');
 1589 
 1590   void _handlePointerEvent(PointerEvent event) {
 1591     FocusHighlightMode expectedMode;
 1592     switch (event.kind) {
 1593       case PointerDeviceKind.touch:
 1594       case PointerDeviceKind.stylus:
 1595       case PointerDeviceKind.invertedStylus:
 1596         _lastInteractionWasTouch = true;
 1597         expectedMode = FocusHighlightMode.touch;
 1598         break;
 1599       case PointerDeviceKind.mouse:
 1600       case PointerDeviceKind.unknown:
 1601         _lastInteractionWasTouch = false;
 1602         expectedMode = FocusHighlightMode.traditional;
 1603         break;
 1604     }
 1605     if (expectedMode != highlightMode) {
 1606       _updateHighlightMode();
 1607     }
 1608   }
 1609 
 1610   bool _handleRawKeyEvent(RawKeyEvent event) {
 1611     // Update highlightMode first, since things responding to the keys might
 1612     // look at the highlight mode, and it should be accurate.
 1613     _lastInteractionWasTouch = false;
 1614     _updateHighlightMode();
 1615 
 1616     assert(_focusDebug('Received key event ${event.logicalKey}'));
 1617     // Walk the current focus from the leaf to the root, calling each one's
 1618     // onKey on the way up, and if one responds that they handled it, stop.
 1619     if (_primaryFocus == null) {
 1620       assert(_focusDebug('No primary focus for key event, ignored: $event'));
 1621       return false;
 1622     }
 1623     bool handled = false;
 1624     for (final FocusNode node in <FocusNode>[_primaryFocus, ..._primaryFocus.ancestors]) {
 1625       if (node.onKey != null && node.onKey(node, event)) {
 1626         assert(_focusDebug('Node $node handled key event $event.'));
 1627         handled = true;
 1628         break;
 1629       }
 1630     }
 1631     if (!handled) {
 1632       assert(_focusDebug('Key event not handled by anyone: $event.'));
 1633     }
 1634     return handled;
 1635   }
 1636 
 1637   /// The node that currently has the primary focus.
 1638   FocusNode get primaryFocus => _primaryFocus;
 1639   FocusNode _primaryFocus;
 1640 
 1641   // The set of nodes that need to notify their listeners of changes at the next
 1642   // update.
 1643   final Set<FocusNode> _dirtyNodes = <FocusNode>{};
 1644 
 1645   // The node that has requested to have the primary focus, but hasn't been
 1646   // given it yet.
 1647   FocusNode _markedForFocus;
 1648 
 1649   void _markDetached(FocusNode node) {
 1650     // The node has been removed from the tree, so it no longer needs to be
 1651     // notified of changes.
 1652     assert(_focusDebug('Node was detached: $node'));
 1653     if (_primaryFocus == node) {
 1654       _primaryFocus = null;
 1655     }
 1656     _dirtyNodes?.remove(node);
 1657   }
 1658 
 1659   void _markPropertiesChanged(FocusNode node) {
 1660     _markNeedsUpdate();
 1661     assert(_focusDebug('Properties changed for node $node.'));
 1662     _dirtyNodes?.add(node);
 1663   }
 1664 
 1665   void _markNextFocus(FocusNode node) {
 1666     if (_primaryFocus == node) {
 1667       // The caller asked for the current focus to be the next focus, so just
 1668       // pretend that didn't happen.
 1669       _markedForFocus = null;
 1670     } else {
 1671       _markedForFocus = node;
 1672       _markNeedsUpdate();
 1673     }
 1674   }
 1675 
 1676   // True indicates that there is an update pending.
 1677   bool _haveScheduledUpdate = false;
 1678 
 1679   // Request that an update be scheduled, optionally requesting focus for the
 1680   // given newFocus node.
 1681   void _markNeedsUpdate() {
 1682     assert(_focusDebug('Scheduling update, current focus is $_primaryFocus, next focus will be $_markedForFocus'));
 1683     if (_haveScheduledUpdate) {
 1684       return;
 1685     }
 1686     _haveScheduledUpdate = true;
 1687     scheduleMicrotask(_applyFocusChange);
 1688   }
 1689 
 1690   void _applyFocusChange() {
 1691     _haveScheduledUpdate = false;
 1692     final FocusNode previousFocus = _primaryFocus;
 1693     if (_primaryFocus == null && _markedForFocus == null) {
 1694       // If we don't have any current focus, and nobody has asked to focus yet,
 1695       // then revert to the root scope.
 1696       _markedForFocus = rootScope;
 1697     }
 1698     assert(_focusDebug('Refreshing focus state. Next focus will be $_markedForFocus'));
 1699     // A node has requested to be the next focus, and isn't already the primary
 1700     // focus.
 1701     if (_markedForFocus != null && _markedForFocus != _primaryFocus) {
 1702       final Set<FocusNode> previousPath = previousFocus?.ancestors?.toSet() ?? <FocusNode>{};
 1703       final Set<FocusNode> nextPath = _markedForFocus.ancestors.toSet();
 1704       // Notify nodes that are newly focused.
 1705       _dirtyNodes.addAll(nextPath.difference(previousPath));
 1706       // Notify nodes that are no longer focused
 1707       _dirtyNodes.addAll(previousPath.difference(nextPath));
 1708 
 1709       _primaryFocus = _markedForFocus;
 1710       _markedForFocus = null;
 1711     }
 1712     if (previousFocus != _primaryFocus) {
 1713       assert(_focusDebug('Updating focus from $previousFocus to $_primaryFocus'));
 1714       if (previousFocus != null) {
 1715         _dirtyNodes.add(previousFocus);
 1716       }
 1717       if (_primaryFocus != null) {
 1718         _dirtyNodes.add(_primaryFocus);
 1719       }
 1720     }
 1721     assert(_focusDebug('Notifying ${_dirtyNodes.length} dirty nodes:', _dirtyNodes.toList().map<String>((FocusNode node) => node.toString())));
 1722     for (final FocusNode node in _dirtyNodes) {
 1723       node._notify();
 1724     }
 1725     _dirtyNodes.clear();
 1726     if (previousFocus != _primaryFocus) {
 1727       notifyListeners();
 1728     }
 1729     assert(() {
 1730       if (_kDebugFocus) {
 1731         debugDumpFocusTree();
 1732       }
 1733       return true;
 1734     }());
 1735   }
 1736 
 1737   @override
 1738   List<DiagnosticsNode> debugDescribeChildren() {
 1739     return <DiagnosticsNode>[
 1740       rootScope.toDiagnosticsNode(name: 'rootScope'),
 1741     ];
 1742   }
 1743 
 1744   @override
 1745   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
 1746     properties.add(FlagProperty('haveScheduledUpdate', value: _haveScheduledUpdate, ifTrue: 'UPDATE SCHEDULED'));
 1747     properties.add(DiagnosticsProperty<FocusNode>('primaryFocus', primaryFocus, defaultValue: null));
 1748     properties.add(DiagnosticsProperty<FocusNode>('nextFocus', _markedForFocus, defaultValue: null));
 1749     final Element element = primaryFocus?.context as Element;
 1750     if (element != null) {
 1751       properties.add(DiagnosticsProperty<String>('primaryFocusCreator', element.debugGetCreatorChain(20)));
 1752     }
 1753   }
 1754 }
 1755 
 1756 /// Provides convenient access to the current [FocusManager.primaryFocus] from the
 1757 /// [WidgetsBinding] instance.
 1758 FocusNode get primaryFocus => WidgetsBinding.instance.focusManager.primaryFocus;
 1759 
 1760 /// Returns a text representation of the current focus tree, along with the
 1761 /// current attributes on each node.
 1762 ///
 1763 /// Will return an empty string in release builds.
 1764 String debugDescribeFocusTree() {
 1765   assert(WidgetsBinding.instance != null);
 1766   String result;
 1767   assert(() {
 1768     result = FocusManager.instance.toStringDeep();
 1769     return true;
 1770   }());
 1771   return result ?? '';
 1772 }
 1773 
 1774 /// Prints a text representation of the current focus tree, along with the
 1775 /// current attributes on each node.
 1776 ///
 1777 /// Will do nothing in release builds.
 1778 void debugDumpFocusTree() {
 1779   assert(() {
 1780     debugPrint(debugDescribeFocusTree());
 1781     return true;
 1782   }());
 1783 }