Fix first focus determination. (#33279)

Replacing the algorithm for finding the first focusable item in the focus tree. Somehow it was a kind of gibberish before, and really didn't work or make sense.
diff --git a/packages/flutter/lib/src/widgets/focus_traversal.dart b/packages/flutter/lib/src/widgets/focus_traversal.dart
index bca61f0..7fb6c72 100644
--- a/packages/flutter/lib/src/widgets/focus_traversal.dart
+++ b/packages/flutter/lib/src/widgets/focus_traversal.dart
@@ -6,6 +6,7 @@
 import 'package:flutter/painting.dart';
 
 import 'basic.dart';
+import 'binding.dart';
 import 'focus_manager.dart';
 import 'framework.dart';
 
@@ -498,16 +499,19 @@
 
   // Moves the focus to the next or previous node, depending on whether forward
   // is true or not.
-  bool _move(FocusNode node, {@required bool forward}) {
-    if (node == null) {
+  bool _move(FocusNode currentNode, {@required bool forward}) {
+    if (currentNode == null) {
       return false;
     }
-    final FocusScopeNode nearestScope = node.nearestScope;
+    final FocusScopeNode nearestScope = currentNode.nearestScope;
     invalidateScopeData(nearestScope);
     final FocusNode focusedChild = nearestScope.focusedChild;
     if (focusedChild == null) {
-      findFirstFocus(node).requestFocus();
-      return true;
+      final FocusNode firstFocus = findFirstFocus(currentNode);
+      if (firstFocus != null) {
+        firstFocus.requestFocus();
+        return true;
+      }
     }
     FocusNode previousNode;
     FocusNode firstNode;
@@ -593,40 +597,22 @@
   @override
   FocusNode findFirstFocus(FocusNode currentNode) {
     assert(currentNode != null);
-    FocusScopeNode scope = currentNode.nearestScope;
-    // Start with the candidate focus as the focused child of this scope, if
-    // there is one. Otherwise start with this node itself. Keep going down
-    // through scopes until an ultimately focusable item is found, a scope
-    // doesn't have a focusedChild, or a non-scope is encountered.
+    final FocusScopeNode scope = currentNode.nearestScope;
     FocusNode candidate = scope.focusedChild;
-    while (candidate == null) {
-      if (candidate.nearestScope.traversalChildren.isNotEmpty) {
-        candidate = _sortByGeometry(scope).first;
-      }
-      if (candidate is FocusScopeNode) {
-        scope = candidate;
-        candidate = scope.focusedChild;
-        continue;
-      }
+    if (candidate == null && scope.traversalChildren.isNotEmpty) {
+      candidate = _sortByGeometry(scope).first;
     }
 
-    if (candidate == null) {
-      if (scope.traversalChildren.isNotEmpty) {
-        candidate = _sortByGeometry(scope).first;
-      } else {
-        candidate = currentNode;
-      }
-    }
-    while (candidate is FocusScopeNode && candidate.focusedChild != null) {
-      final FocusScopeNode candidateScope = candidate;
-      candidate = candidateScope.focusedChild;
-    }
+    // If we still didn't find any candidate, use the current node as a
+    // fallback.
+    candidate ??= currentNode;
+    candidate ??= WidgetsBinding.instance.focusManager.rootScope;
     return candidate;
   }
 
   // Sorts the list of nodes based on their geometry into the desired reading
   // order based on the directionality of the context for each node.
-  Iterable<FocusNode> _sortByGeometry(FocusNode scope) {
+  Iterable<FocusNode> _sortByGeometry(FocusScopeNode scope) {
     final Iterable<FocusNode> nodes = scope.traversalDescendants;
     if (nodes.length <= 1) {
       return nodes;
@@ -691,8 +677,11 @@
     invalidateScopeData(nearestScope);
     final FocusNode focusedChild = nearestScope.focusedChild;
     if (focusedChild == null) {
-      findFirstFocus(currentNode).requestFocus();
-      return true;
+      final FocusNode firstFocus = findFirstFocus(currentNode);
+      if (firstFocus != null) {
+        firstFocus.requestFocus();
+        return true;
+      }
     }
     final List<FocusNode> sortedNodes = _sortByGeometry(nearestScope).toList();
     if (forward && focusedChild == sortedNodes.last) {
diff --git a/packages/flutter/test/widgets/focus_traversal_test.dart b/packages/flutter/test/widgets/focus_traversal_test.dart
index 1838456..693ffb1 100644
--- a/packages/flutter/test/widgets/focus_traversal_test.dart
+++ b/packages/flutter/test/widgets/focus_traversal_test.dart
@@ -8,6 +8,44 @@
 
 void main() {
   group(WidgetOrderFocusTraversalPolicy, () {
+    testWidgets('Find the initial focus if there is none yet.', (WidgetTester tester) async {
+      final GlobalKey key1 = GlobalKey(debugLabel: '1');
+      final GlobalKey key2 = GlobalKey(debugLabel: '2');
+      final GlobalKey key3 = GlobalKey(debugLabel: '3');
+      final GlobalKey key4 = GlobalKey(debugLabel: '4');
+      final GlobalKey key5 = GlobalKey(debugLabel: '5');
+      await tester.pumpWidget(DefaultFocusTraversal(
+        policy: WidgetOrderFocusTraversalPolicy(),
+        child: FocusScope(
+          key: key1,
+          child: Column(
+            children: <Widget>[
+              Focus(
+                key: key2,
+                child: Container(key: key3, width: 100, height: 100),
+              ),
+              Focus(
+                key: key4,
+                child: Container(key: key5, width: 100, height: 100),
+              ),
+            ],
+          ),
+        ),
+      ));
+
+      final Element firstChild = tester.element(find.byKey(key3));
+      final Element secondChild = tester.element(find.byKey(key5));
+      final FocusNode firstFocusNode = Focus.of(firstChild);
+      final FocusNode secondFocusNode = Focus.of(secondChild);
+      final FocusNode scope = Focus.of(firstChild).enclosingScope;
+      secondFocusNode.nextFocus();
+
+      await tester.pump();
+
+      expect(firstFocusNode.hasFocus, isTrue);
+      expect(secondFocusNode.hasFocus, isFalse);
+      expect(scope.hasFocus, isTrue);
+    });
     testWidgets('Move focus to next node.', (WidgetTester tester) async {
       final GlobalKey key1 = GlobalKey(debugLabel: '1');
       final GlobalKey key2 = GlobalKey(debugLabel: '2');
@@ -199,6 +237,44 @@
     });
   });
   group(ReadingOrderTraversalPolicy, () {
+    testWidgets('Find the initial focus if there is none yet.', (WidgetTester tester) async {
+      final GlobalKey key1 = GlobalKey(debugLabel: '1');
+      final GlobalKey key2 = GlobalKey(debugLabel: '2');
+      final GlobalKey key3 = GlobalKey(debugLabel: '3');
+      final GlobalKey key4 = GlobalKey(debugLabel: '4');
+      final GlobalKey key5 = GlobalKey(debugLabel: '5');
+      await tester.pumpWidget(DefaultFocusTraversal(
+        policy: ReadingOrderTraversalPolicy(),
+        child: FocusScope(
+          key: key1,
+          child: Column(
+            children: <Widget>[
+              Focus(
+                key: key2,
+                child: Container(key: key3, width: 100, height: 100),
+              ),
+              Focus(
+                key: key4,
+                child: Container(key: key5, width: 100, height: 100),
+              ),
+            ],
+          ),
+        ),
+      ));
+
+      final Element firstChild = tester.element(find.byKey(key3));
+      final Element secondChild = tester.element(find.byKey(key5));
+      final FocusNode firstFocusNode = Focus.of(firstChild);
+      final FocusNode secondFocusNode = Focus.of(secondChild);
+      final FocusNode scope = Focus.of(firstChild).enclosingScope;
+      secondFocusNode.nextFocus();
+
+      await tester.pump();
+
+      expect(firstFocusNode.hasFocus, isTrue);
+      expect(secondFocusNode.hasFocus, isFalse);
+      expect(scope.hasFocus, isTrue);
+    });
     testWidgets('Move reading focus to next node.', (WidgetTester tester) async {
       final GlobalKey key1 = GlobalKey(debugLabel: '1');
       final GlobalKey key2 = GlobalKey(debugLabel: '2');