@@ -1367,35 +1367,6 @@ class FocusManager with DiagnosticableTreeMixin, ChangeNotifier {
1367
1367
/// the [WidgetsBinding] instance.
1368
1368
static FocusManager get instance => WidgetsBinding .instance.focusManager;
1369
1369
1370
- bool get _lastInteractionWasTouch {
1371
- // Assume that if we're on one of these mobile platforms, or if there's no
1372
- // mouse connected, that the initial interaction will be touch-based, and
1373
- // that it's traditional mouse and keyboard on all others.
1374
- //
1375
- // This only affects the initial value: the ongoing value is updated to a
1376
- // known correct value as soon as any pointer events are received.
1377
- if (_lastInteractionWasTouchValue == null ) {
1378
- switch (defaultTargetPlatform) {
1379
- case TargetPlatform .android:
1380
- case TargetPlatform .fuchsia:
1381
- case TargetPlatform .iOS:
1382
- _lastInteractionWasTouchValue = ! WidgetsBinding .instance.mouseTracker.mouseIsConnected;
1383
- break ;
1384
- case TargetPlatform .linux:
1385
- case TargetPlatform .macOS:
1386
- case TargetPlatform .windows:
1387
- _lastInteractionWasTouchValue = false ;
1388
- break ;
1389
- }
1390
- }
1391
- return _lastInteractionWasTouchValue;
1392
- }
1393
- bool _lastInteractionWasTouchValue;
1394
- set _lastInteractionWasTouch (bool value) {
1395
- _lastInteractionWasTouchValue = value;
1396
- }
1397
-
1398
-
1399
1370
/// Sets the strategy by which [highlightMode] is determined.
1400
1371
///
1401
1372
/// If set to [FocusHighlightStrategy.automatic] , then the highlight mode will
@@ -1427,6 +1398,30 @@ class FocusManager with DiagnosticableTreeMixin, ChangeNotifier {
1427
1398
_updateHighlightMode ();
1428
1399
}
1429
1400
1401
+ static FocusHighlightMode get _defaultModeForPlatform {
1402
+ // Assume that if we're on one of the mobile platforms, and there's no mouse
1403
+ // connected, that the initial interaction will be touch-based, and that
1404
+ // it's traditional mouse and keyboard on all other platforms.
1405
+ //
1406
+ // This only affects the initial value: the ongoing value is updated to a
1407
+ // known correct value as soon as any pointer/keyboard events are received.
1408
+ switch (defaultTargetPlatform) {
1409
+ case TargetPlatform .android:
1410
+ case TargetPlatform .fuchsia:
1411
+ case TargetPlatform .iOS:
1412
+ if (WidgetsBinding .instance.mouseTracker.mouseIsConnected) {
1413
+ return FocusHighlightMode .traditional;
1414
+ }
1415
+ return FocusHighlightMode .touch;
1416
+ case TargetPlatform .linux:
1417
+ case TargetPlatform .macOS:
1418
+ case TargetPlatform .windows:
1419
+ return FocusHighlightMode .traditional;
1420
+ }
1421
+ assert (false , 'Unhandled target platform $defaultTargetPlatform ' );
1422
+ return null ;
1423
+ }
1424
+
1430
1425
/// Indicates the current interaction mode for focus highlights.
1431
1426
///
1432
1427
/// The value returned depends upon the [highlightStrategy] used, and possibly
@@ -1438,15 +1433,28 @@ class FocusManager with DiagnosticableTreeMixin, ChangeNotifier {
1438
1433
///
1439
1434
/// If [highlightMode] returns [FocusHighlightMode.traditional] , then widgets should
1440
1435
/// draw their focus highlight whenever they are focused.
1441
- FocusHighlightMode get highlightMode => _highlightMode;
1442
- FocusHighlightMode _highlightMode = FocusHighlightMode .touch;
1436
+ // Don't want to set _highlightMode here, since it's possible for the target
1437
+ // platform to change (especially in tests).
1438
+ FocusHighlightMode get highlightMode => _highlightMode ?? _defaultModeForPlatform;
1439
+ FocusHighlightMode _highlightMode;
1440
+
1441
+ // If set, indicates if the last interaction detected was touch or not.
1442
+ // If null, no interactions have occurred yet.
1443
+ bool _lastInteractionWasTouch;
1443
1444
1444
1445
// Update function to be called whenever the state relating to highlightMode
1445
1446
// changes.
1446
1447
void _updateHighlightMode () {
1447
1448
FocusHighlightMode newMode;
1448
1449
switch (highlightStrategy) {
1449
1450
case FocusHighlightStrategy .automatic:
1451
+ if (_lastInteractionWasTouch == null ) {
1452
+ // If we don't have any information about the last interaction yet,
1453
+ // then just rely on the default value for the platform, which will be
1454
+ // determined based on the target platform if _highlightMode is not
1455
+ // set.
1456
+ return ;
1457
+ }
1450
1458
if (_lastInteractionWasTouch) {
1451
1459
newMode = FocusHighlightMode .touch;
1452
1460
} else {
@@ -1460,8 +1468,12 @@ class FocusManager with DiagnosticableTreeMixin, ChangeNotifier {
1460
1468
newMode = FocusHighlightMode .traditional;
1461
1469
break ;
1462
1470
}
1463
- if (newMode != _highlightMode) {
1464
- _highlightMode = newMode;
1471
+ // We can't just compare newMode with _highlightMode here, since
1472
+ // _highlightMode could be null, so we want to compare with the return value
1473
+ // for the getter, since that's what clients will be looking at.
1474
+ final FocusHighlightMode oldMode = highlightMode;
1475
+ _highlightMode = newMode;
1476
+ if (highlightMode != oldMode) {
1465
1477
_notifyHighlightModeListeners ();
1466
1478
}
1467
1479
}
@@ -1485,7 +1497,7 @@ class FocusManager with DiagnosticableTreeMixin, ChangeNotifier {
1485
1497
for (final ValueChanged <FocusHighlightMode > listener in localListeners) {
1486
1498
try {
1487
1499
if (_listeners.contains (listener)) {
1488
- listener (_highlightMode );
1500
+ listener (highlightMode );
1489
1501
}
1490
1502
} catch (exception, stack) {
1491
1503
InformationCollector collector;
@@ -1517,31 +1529,30 @@ class FocusManager with DiagnosticableTreeMixin, ChangeNotifier {
1517
1529
final FocusScopeNode rootScope = FocusScopeNode (debugLabel: 'Root Focus Scope' );
1518
1530
1519
1531
void _handlePointerEvent (PointerEvent event) {
1520
- bool currentInteractionIsTouch ;
1532
+ FocusHighlightMode expectedMode ;
1521
1533
switch (event.kind) {
1522
1534
case PointerDeviceKind .touch:
1523
1535
case PointerDeviceKind .stylus:
1524
1536
case PointerDeviceKind .invertedStylus:
1525
- currentInteractionIsTouch = true ;
1537
+ _lastInteractionWasTouch = true ;
1538
+ expectedMode = FocusHighlightMode .touch;
1526
1539
break ;
1527
1540
case PointerDeviceKind .mouse:
1528
1541
case PointerDeviceKind .unknown:
1529
- currentInteractionIsTouch = false ;
1542
+ _lastInteractionWasTouch = false ;
1543
+ expectedMode = FocusHighlightMode .traditional;
1530
1544
break ;
1531
1545
}
1532
- if (_lastInteractionWasTouch != currentInteractionIsTouch) {
1533
- _lastInteractionWasTouch = currentInteractionIsTouch;
1546
+ if (expectedMode != highlightMode) {
1534
1547
_updateHighlightMode ();
1535
1548
}
1536
1549
}
1537
1550
1538
1551
void _handleRawKeyEvent (RawKeyEvent event) {
1539
1552
// Update highlightMode first, since things responding to the keys might
1540
1553
// look at the highlight mode, and it should be accurate.
1541
- if (_lastInteractionWasTouch) {
1542
- _lastInteractionWasTouch = false ;
1543
- _updateHighlightMode ();
1544
- }
1554
+ _lastInteractionWasTouch = false ;
1555
+ _updateHighlightMode ();
1545
1556
1546
1557
assert (_focusDebug ('Received key event ${event .logicalKey }' ));
1547
1558
// Walk the current focus from the leaf to the root, calling each one's
0 commit comments