Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Sign in
Toggle navigation
F
Front-End
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
abdullh.alsoleman
Front-End
Commits
b1b7284a
Unverified
Commit
b1b7284a
authored
Feb 24, 2023
by
Michael Goderbauer
Committed by
GitHub
Feb 24, 2023
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Move semantic-related bindings to SemanticsBinding (#121289)
Move semantic-related bindings to SemanticsBinding
parent
cb67ecd9
Changes
12
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
339 additions
and
88 deletions
+339
-88
smoke_test.dart
dev/integration_tests/flutter_gallery/test/smoke_test.dart
+2
-2
main.dart
...ion_tests/ios_add2app_life_cycle/flutterapp/lib/main.dart
+54
-9
binding.dart
packages/flutter/lib/src/rendering/binding.dart
+15
-25
object.dart
packages/flutter/lib/src/rendering/object.dart
+10
-27
binding.dart
packages/flutter/lib/src/semantics/binding.dart
+161
-13
semantics.dart
packages/flutter/lib/src/semantics/semantics.dart
+3
-3
binding.dart
packages/flutter/lib/src/widgets/binding.dart
+0
-1
semantics_binding_test.dart
packages/flutter/test/semantics/semantics_binding_test.dart
+84
-0
binding_cannot_schedule_frame_test.dart
...tter/test/widgets/binding_cannot_schedule_frame_test.dart
+3
-1
handler_factory.dart
packages/flutter_driver/lib/src/common/handler_factory.dart
+2
-2
controller.dart
packages/flutter_test/lib/src/controller.dart
+3
-3
finders.dart
packages/flutter_test/lib/src/finders.dart
+2
-2
No files found.
dev/integration_tests/flutter_gallery/test/smoke_test.dart
View file @
b1b7284a
...
...
@@ -184,8 +184,8 @@ void main() {
);
testWidgets
(
'Flutter Gallery app smoke test with semantics'
,
(
WidgetTester
tester
)
async
{
RendererBinding
.
instance
.
setSemanticsEnabled
(
true
);
final
SemanticsHandle
handle
=
SemanticsBinding
.
instance
.
ensureSemantics
(
);
await
smokeGallery
(
tester
);
RendererBinding
.
instance
.
setSemanticsEnabled
(
false
);
handle
.
dispose
(
);
});
}
dev/integration_tests/ios_add2app_life_cycle/flutterapp/lib/main.dart
View file @
b1b7284a
...
...
@@ -3,19 +3,16 @@
// found in the LICENSE file.
import
'package:collection/collection.dart'
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/material.dart'
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/services.dart'
;
VoidCallback
?
originalSemanticsListener
;
void
main
(
)
{
WidgetsFlutterBinding
.
ensureInitialized
();
// Disconnects semantics listener for testing purposes.
originalSemanticsListener
=
WidgetsBinding
.
instance
.
platformDispatcher
.
onSemanticsEnabledChanged
;
RendererBinding
.
instance
.
platformDispatcher
.
onSemanticsEnabledChanged
=
null
;
RendererBinding
.
instance
.
setSemanticsEnabled
(
false
);
// If the test passes, LifeCycleSpy will rewire the semantics listener back.
SwitchableSemanticsBinding
.
ensureInitialized
();
assert
(!
SwitchableSemanticsBinding
.
instance
.
semanticsEnabled
);
runApp
(
const
LifeCycleSpy
());
}
...
...
@@ -68,8 +65,7 @@ class _LifeCycleSpyState extends State<LifeCycleSpy> with WidgetsBindingObserver
Widget
build
(
BuildContext
context
)
{
if
(
const
ListEquality
<
AppLifecycleState
?>().
equals
(
_actualLifeCycleSequence
,
_expectedLifeCycleSequence
))
{
// Rewires the semantics harness if test passes.
RendererBinding
.
instance
.
setSemanticsEnabled
(
true
);
RendererBinding
.
instance
.
platformDispatcher
.
onSemanticsEnabledChanged
=
originalSemanticsListener
;
SwitchableSemanticsBinding
.
instance
.
semanticsEnabled
=
true
;
}
return
const
MaterialApp
(
title:
'Flutter View'
,
...
...
@@ -77,3 +73,52 @@ class _LifeCycleSpyState extends State<LifeCycleSpy> with WidgetsBindingObserver
);
}
}
class
SwitchableSemanticsBinding
extends
WidgetsFlutterBinding
{
static
SwitchableSemanticsBinding
get
instance
=>
BindingBase
.
checkInstance
(
_instance
);
static
SwitchableSemanticsBinding
?
_instance
;
static
SwitchableSemanticsBinding
ensureInitialized
()
{
if
(
_instance
==
null
)
{
SwitchableSemanticsBinding
();
}
return
SwitchableSemanticsBinding
.
instance
;
}
VoidCallback
?
_originalSemanticsListener
;
@override
void
initInstances
()
{
super
.
initInstances
();
_instance
=
this
;
_updateHandler
();
}
@override
bool
get
semanticsEnabled
=>
_semanticsEnabled
.
value
;
final
ValueNotifier
<
bool
>
_semanticsEnabled
=
ValueNotifier
<
bool
>(
false
);
set
semanticsEnabled
(
bool
value
)
{
_semanticsEnabled
.
value
=
value
;
_updateHandler
();
}
void
_updateHandler
()
{
if
(
_semanticsEnabled
.
value
)
{
platformDispatcher
.
onSemanticsEnabledChanged
=
_originalSemanticsListener
;
_originalSemanticsListener
=
null
;
}
else
{
_originalSemanticsListener
=
platformDispatcher
.
onSemanticsEnabledChanged
;
platformDispatcher
.
onSemanticsEnabledChanged
=
null
;
}
}
@override
void
addSemanticsEnabledListener
(
VoidCallback
listener
)
{
_semanticsEnabled
.
addListener
(
listener
);
}
@override
void
removeSemanticsEnabledListener
(
VoidCallback
listener
)
{
_semanticsEnabled
.
removeListener
(
listener
);
}
}
packages/flutter/lib/src/rendering/binding.dart
View file @
b1b7284a
...
...
@@ -38,16 +38,15 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture
platformDispatcher
..
onMetricsChanged
=
handleMetricsChanged
..
onTextScaleFactorChanged
=
handleTextScaleFactorChanged
..
onPlatformBrightnessChanged
=
handlePlatformBrightnessChanged
..
onSemanticsEnabledChanged
=
_handleSemanticsEnabledChanged
..
onSemanticsAction
=
_handleSemanticsAction
;
..
onPlatformBrightnessChanged
=
handlePlatformBrightnessChanged
;
initRenderView
();
_handleSemanticsEnabledChanged
();
addPersistentFrameCallback
(
_handlePersistentFrameCallback
);
initMouseTracker
();
if
(
kIsWeb
)
{
addPostFrameCallback
(
_handleWebFirstFrame
);
}
addSemanticsEnabledListener
(
_handleSemanticsEnabledChanged
);
_handleSemanticsEnabledChanged
();
}
/// The current [RendererBinding], if one has been created.
...
...
@@ -308,8 +307,6 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture
);
}
SemanticsHandle
?
_semanticsHandle
;
/// Creates a [MouseTracker] which manages state about currently connected
/// mice, for hover notification.
///
...
...
@@ -333,14 +330,10 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture
super
.
dispatchEvent
(
event
,
hitTestResult
);
}
void
_handleSemanticsEnabledChanged
()
{
setSemanticsEnabled
(
platformDispatcher
.
semanticsEnabled
);
}
SemanticsHandle
?
_semanticsHandle
;
/// Whether the render tree associated with this binding should produce a tree
/// of [SemanticsNode] objects.
void
setSemanticsEnabled
(
bool
enabled
)
{
if
(
enabled
)
{
void
_handleSemanticsEnabledChanged
()
{
if
(
semanticsEnabled
)
{
_semanticsHandle
??=
_pipelineOwner
.
ensureSemantics
();
}
else
{
_semanticsHandle
?.
dispose
();
...
...
@@ -348,18 +341,9 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture
}
}
void
_handleWebFirstFrame
(
Duration
_
)
{
assert
(
kIsWeb
);
const
MethodChannel
methodChannel
=
MethodChannel
(
'flutter/service_worker'
);
methodChannel
.
invokeMethod
<
void
>(
'first-frame'
);
}
void
_handleSemanticsAction
(
int
id
,
SemanticsAction
action
,
ByteData
?
args
)
{
_pipelineOwner
.
semanticsOwner
?.
performAction
(
id
,
action
,
args
!=
null
?
const
StandardMessageCodec
().
decodeMessage
(
args
)
:
null
,
);
@override
void
performSemanticsAction
(
SemanticsActionEvent
action
)
{
_pipelineOwner
.
semanticsOwner
?.
performAction
(
action
.
nodeId
,
action
.
type
,
action
.
arguments
);
}
void
_handleSemanticsOwnerCreated
()
{
...
...
@@ -374,6 +358,12 @@ mixin RendererBinding on BindingBase, ServicesBinding, SchedulerBinding, Gesture
renderView
.
clearSemantics
();
}
void
_handleWebFirstFrame
(
Duration
_
)
{
assert
(
kIsWeb
);
const
MethodChannel
methodChannel
=
MethodChannel
(
'flutter/service_worker'
);
methodChannel
.
invokeMethod
<
void
>(
'first-frame'
);
}
void
_handlePersistentFrameCallback
(
Duration
timeStamp
)
{
drawFrame
();
_scheduleMouseTrackerUpdate
();
...
...
packages/flutter/lib/src/rendering/object.dart
View file @
b1b7284a
...
...
@@ -808,24 +808,8 @@ typedef RenderObjectVisitor = void Function(RenderObject child);
/// Used by [RenderObject.invokeLayoutCallback].
typedef
LayoutCallback
<
T
extends
Constraints
>
=
void
Function
(
T
constraints
);
/// A reference to the semantics tree.
///
/// The framework maintains the semantics tree (used for accessibility and
/// indexing) only when there is at least one client holding an open
/// [SemanticsHandle].
///
/// The framework notifies the client that it has updated the semantics tree by
/// calling the [listener] callback. When the client no longer needs the
/// semantics tree, the client can call [dispose] on the [SemanticsHandle],
/// which stops these callbacks and closes the [SemanticsHandle]. When all the
/// outstanding [SemanticsHandle] objects are closed, the framework stops
/// updating the semantics tree.
///
/// To obtain a [SemanticsHandle], call [PipelineOwner.ensureSemantics] on the
/// [PipelineOwner] for the render tree from which you wish to read semantics.
/// You can obtain the [PipelineOwner] using the [RenderObject.owner] property.
class
SemanticsHandle
{
SemanticsHandle
.
_
(
PipelineOwner
owner
,
this
.
listener
)
class
_LocalSemanticsHandle
implements
SemanticsHandle
{
_LocalSemanticsHandle
.
_
(
PipelineOwner
owner
,
this
.
listener
)
:
_owner
=
owner
{
if
(
listener
!=
null
)
{
_owner
.
semanticsOwner
!.
addListener
(
listener
!);
...
...
@@ -837,13 +821,7 @@ class SemanticsHandle {
/// The callback that will be notified when the semantics tree updates.
final
VoidCallback
?
listener
;
/// Closes the semantics handle and stops calling [listener] when the
/// semantics updates.
///
/// When all the outstanding [SemanticsHandle] objects for a given
/// [PipelineOwner] are closed, the [PipelineOwner] will stop updating the
/// semantics tree.
@mustCallSuper
@override
void
dispose
()
{
if
(
listener
!=
null
)
{
_owner
.
semanticsOwner
!.
removeListener
(
listener
!);
...
...
@@ -1171,7 +1149,12 @@ class PipelineOwner {
int
_outstandingSemanticsHandles
=
0
;
/// Opens a [SemanticsHandle] and calls [listener] whenever the semantics tree
/// updates.
/// generated from the render tree owned by this [PipelineOwner] updates.
///
/// Calling this method only ensures that this particular [PipelineOwner] will
/// generate a semantics tree. Consider calling
/// [SemanticsBinding.ensureSemantics] instead to turn on semantics globally
/// for the entire app.
///
/// The [PipelineOwner] updates the semantics tree only when there are clients
/// that wish to use the semantics tree. These clients express their interest
...
...
@@ -1190,7 +1173,7 @@ class PipelineOwner {
_semanticsOwner
=
SemanticsOwner
(
onSemanticsUpdate:
onSemanticsUpdate
!);
onSemanticsOwnerCreated
?.
call
();
}
return
SemanticsHandle
.
_
(
this
,
listener
);
return
_Local
SemanticsHandle
.
_
(
this
,
listener
);
}
void
_didDisposeSemanticsHandle
()
{
...
...
packages/flutter/lib/src/semantics/binding.dart
View file @
b1b7284a
...
...
@@ -2,22 +2,27 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'dart:ui'
as
ui
show
AccessibilityFeatures
,
SemanticsUpdateBuilder
;
import
'dart:ui'
as
ui
show
AccessibilityFeatures
,
Semantics
Action
,
Semantics
UpdateBuilder
;
import
'package:flutter/foundation.dart'
;
import
'package:flutter/services.dart'
;
import
'debug.dart'
;
export
'dart:ui'
show
AccessibilityFeatures
,
SemanticsUpdateBuilder
;
/// The glue between the semantics layer and the Flutter engine.
// TODO(zanderso): move the remaining semantic related bindings here.
mixin
SemanticsBinding
on
BindingBase
{
@override
void
initInstances
()
{
super
.
initInstances
();
_instance
=
this
;
_accessibilityFeatures
=
platformDispatcher
.
accessibilityFeatures
;
platformDispatcher
..
onSemanticsEnabledChanged
=
_handleSemanticsEnabledChanged
..
onSemanticsAction
=
_handleSemanticsAction
..
onAccessibilityFeaturesChanged
=
handleAccessibilityFeaturesChanged
;
_handleSemanticsEnabledChanged
();
}
/// The current [SemanticsBinding], if one has been created.
...
...
@@ -28,10 +33,118 @@ mixin SemanticsBinding on BindingBase {
static
SemanticsBinding
get
instance
=>
BindingBase
.
checkInstance
(
_instance
);
static
SemanticsBinding
?
_instance
;
/// Whether semantics information must be collected.
///
/// Returns true if either the platform has requested semantics information
/// to be generated or if [ensureSemantics] has been called otherwise.
///
/// To get notified when this value changes register a listener with
/// [addSemanticsEnabledListener].
bool
get
semanticsEnabled
{
assert
(
_semanticsEnabled
.
value
==
(
_outstandingHandles
>
0
));
return
_semanticsEnabled
.
value
;
}
late
final
ValueNotifier
<
bool
>
_semanticsEnabled
=
ValueNotifier
<
bool
>(
platformDispatcher
.
semanticsEnabled
);
/// Adds a `listener` to be called when [semanticsEnabled] changes.
///
/// See also:
///
/// * [removeSemanticsEnabledListener] to remove the listener again.
/// * [ValueNotifier.addListener], which documents how and when listeners are
/// called.
void
addSemanticsEnabledListener
(
VoidCallback
listener
)
{
_semanticsEnabled
.
addListener
(
listener
);
}
/// Removes a `listener` added by [addSemanticsEnabledListener].
///
/// See also:
///
/// * [ValueNotifier.removeListener], which documents how listeners are
/// removed.
void
removeSemanticsEnabledListener
(
VoidCallback
listener
)
{
_semanticsEnabled
.
removeListener
(
listener
);
}
int
_outstandingHandles
=
0
;
/// Creates a new [SemanticsHandle] and requests the collection of semantics
/// information.
///
/// Semantics information are only collected when there are clients interested
/// in them. These clients express their interest by holding a
/// [SemanticsHandle].
///
/// Clients can close their [SemanticsHandle] by calling
/// [SemanticsHandle.dispose]. Once all outstanding [SemanticsHandle] objects
/// are closed, semantics information are no longer collected.
SemanticsHandle
ensureSemantics
()
{
assert
(
_outstandingHandles
>=
0
);
_outstandingHandles
++;
assert
(
_outstandingHandles
>
0
);
_semanticsEnabled
.
value
=
true
;
return
SemanticsHandle
.
_
(
_didDisposeSemanticsHandle
);
}
void
_didDisposeSemanticsHandle
()
{
assert
(
_outstandingHandles
>
0
);
_outstandingHandles
--;
assert
(
_outstandingHandles
>=
0
);
_semanticsEnabled
.
value
=
_outstandingHandles
>
0
;
}
// Handle for semantics request from the platform.
SemanticsHandle
?
_semanticsHandle
;
void
_handleSemanticsEnabledChanged
()
{
if
(
platformDispatcher
.
semanticsEnabled
)
{
_semanticsHandle
??=
ensureSemantics
();
}
else
{
_semanticsHandle
?.
dispose
();
_semanticsHandle
=
null
;
}
}
void
_handleSemanticsAction
(
int
id
,
ui
.
SemanticsAction
action
,
ByteData
?
args
)
{
performSemanticsAction
(
SemanticsActionEvent
(
nodeId:
id
,
type:
action
,
arguments:
args
!=
null
?
const
StandardMessageCodec
().
decodeMessage
(
args
)
:
null
,
));
}
/// Called whenever the platform requests an action to be performed on a
/// [SemanticsNode].
///
/// This callback is invoked when a user interacts with the app via an
/// accessibility service (e.g. TalkBack and VoiceOver) and initiates an
/// action on the focused node.
///
/// Bindings that mixin the [SemanticsBinding] must implement this method and
/// perform the given `action` on the [SemanticsNode] specified by
/// [SemanticsActionEvent.nodeId].
///
/// See [dart:ui.PlatformDispatcher.onSemanticsAction].
@protected
void
performSemanticsAction
(
SemanticsActionEvent
action
);
/// The currently active set of [AccessibilityFeatures].
///
/// This is set when the binding is first initialized and updated whenever a
/// flag is changed.
///
/// To listen to changes to accessibility features, create a
/// [WidgetsBindingObserver] and listen to
/// [WidgetsBindingObserver.didChangeAccessibilityFeatures].
ui
.
AccessibilityFeatures
get
accessibilityFeatures
=>
_accessibilityFeatures
;
late
ui
.
AccessibilityFeatures
_accessibilityFeatures
;
/// Called when the platform accessibility features change.
///
/// See [dart:ui.PlatformDispatcher.onAccessibilityFeaturesChanged].
@protected
@mustCallSuper
void
handleAccessibilityFeaturesChanged
()
{
_accessibilityFeatures
=
platformDispatcher
.
accessibilityFeatures
;
}
...
...
@@ -46,17 +159,6 @@ mixin SemanticsBinding on BindingBase {
return
ui
.
SemanticsUpdateBuilder
();
}
/// The currently active set of [AccessibilityFeatures].
///
/// This is initialized the first time [runApp] is called and updated whenever
/// a flag is changed.
///
/// To listen to changes to accessibility features, create a
/// [WidgetsBindingObserver] and listen to
/// [WidgetsBindingObserver.didChangeAccessibilityFeatures].
ui
.
AccessibilityFeatures
get
accessibilityFeatures
=>
_accessibilityFeatures
;
late
ui
.
AccessibilityFeatures
_accessibilityFeatures
;
/// The platform is requesting that animations be disabled or simplified.
///
/// This setting can be overridden for testing or debugging by setting
...
...
@@ -72,3 +174,49 @@ mixin SemanticsBinding on BindingBase {
return
value
;
}
}
/// An event to request a [SemanticsAction] of [type] to be performed on the
/// [SemanticsNode] identified by [nodeId].
///
/// Used by [SemanticsBinding.performSemanticsAction].
@immutable
class
SemanticsActionEvent
{
/// Creates a [SemanticsActionEvent].
///
/// The [type] and [nodeId] are required.
const
SemanticsActionEvent
({
required
this
.
type
,
required
this
.
nodeId
,
this
.
arguments
});
/// The type of action to be performed.
final
ui
.
SemanticsAction
type
;
/// The id of the [SemanticsNode] on which the action is to be performed.
final
int
nodeId
;
/// Optional arguments for the action.
final
Object
?
arguments
;
}
/// A reference to the semantics information generated by the framework.
///
/// Semantics information are only collected when there are clients interested
/// in them. These clients express their interest by holding a
/// [SemanticsHandle]. When the client no longer needs the
/// semantics information, it must call [dispose] on the [SemanticsHandle] to
/// close it. When all open [SemanticsHandle]s are disposed, the framework will
/// stop updating the semantics information.
///
/// To obtain a [SemanticsHandle], call [SemanticsBinding.ensureSemantics].
class
SemanticsHandle
{
SemanticsHandle
.
_
(
this
.
_onDispose
);
final
VoidCallback
_onDispose
;
/// Closes the semantics handle.
///
/// When all the outstanding [SemanticsHandle] objects are closed, the
/// framework will stop generating semantics information.
@mustCallSuper
void
dispose
()
{
_onDispose
();
}
}
packages/flutter/lib/src/semantics/semantics.dart
View file @
b1b7284a
...
...
@@ -3129,9 +3129,9 @@ class _TraversalSortNode implements Comparable<_TraversalSortNode> {
/// Owns [SemanticsNode] objects and notifies listeners of changes to the
/// render tree semantics.
///
/// To listen for semantic updates, call [
PipelineOwner.ensureSemantics] to
///
obtain a [SemanticsHandle]. This will create a [SemanticsOwner] if
/// necessary.
/// To listen for semantic updates, call [
SemanticsBinding.ensureSemantics] or
///
[PipelineOwner.ensureSemantics] to obtain a [SemanticsHandle]. This will
///
create a [SemanticsOwner] if
necessary.
class
SemanticsOwner
extends
ChangeNotifier
{
/// Creates a [SemanticsOwner] that manages zero or more [SemanticsNode] objects.
SemanticsOwner
({
...
...
packages/flutter/lib/src/widgets/binding.dart
View file @
b1b7284a
...
...
@@ -260,7 +260,6 @@ mixin WidgetsBinding on BindingBase, ServicesBinding, SchedulerBinding, GestureB
_buildOwner
=
BuildOwner
();
buildOwner
!.
onBuildScheduled
=
_handleBuildScheduled
;
platformDispatcher
.
onLocaleChanged
=
handleLocaleChanged
;
platformDispatcher
.
onAccessibilityFeaturesChanged
=
handleAccessibilityFeaturesChanged
;
SystemChannels
.
navigation
.
setMethodCallHandler
(
_handleNavigationInvocation
);
assert
(()
{
FlutterErrorDetails
.
propertiesTransformers
.
add
(
debugTransformDebugCreator
);
...
...
packages/flutter/test/semantics/semantics_binding_test.dart
0 → 100644
View file @
b1b7284a
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter/semantics.dart'
;
import
'package:flutter_test/flutter_test.dart'
;
void
main
(
)
{
testWidgets
(
'Listeners are called when semantics are turned on with ensureSemantics'
,
(
WidgetTester
tester
)
async
{
expect
(
SemanticsBinding
.
instance
.
semanticsEnabled
,
isFalse
);
final
List
<
bool
>
status
=
<
bool
>[];
void
listener
()
{
status
.
add
(
SemanticsBinding
.
instance
.
semanticsEnabled
);
}
SemanticsBinding
.
instance
.
addSemanticsEnabledListener
(
listener
);
expect
(
SemanticsBinding
.
instance
.
semanticsEnabled
,
isFalse
);
final
SemanticsHandle
handle1
=
SemanticsBinding
.
instance
.
ensureSemantics
();
expect
(
status
.
single
,
isTrue
);
expect
(
SemanticsBinding
.
instance
.
semanticsEnabled
,
isTrue
);
status
.
clear
();
final
SemanticsHandle
handle2
=
SemanticsBinding
.
instance
.
ensureSemantics
();
expect
(
status
,
isEmpty
);
// Listener didn't fire again.
expect
(
SemanticsBinding
.
instance
.
semanticsEnabled
,
isTrue
);
expect
(
tester
.
binding
.
platformDispatcher
.
semanticsEnabled
,
isFalse
);
tester
.
binding
.
platformDispatcher
.
semanticsEnabledTestValue
=
true
;
expect
(
tester
.
binding
.
platformDispatcher
.
semanticsEnabled
,
isTrue
);
tester
.
binding
.
platformDispatcher
.
clearSemanticsEnabledTestValue
();
expect
(
tester
.
binding
.
platformDispatcher
.
semanticsEnabled
,
isFalse
);
expect
(
status
,
isEmpty
);
// Listener didn't fire again.
expect
(
SemanticsBinding
.
instance
.
semanticsEnabled
,
isTrue
);
handle1
.
dispose
();
expect
(
status
,
isEmpty
);
// Listener didn't fire.
expect
(
SemanticsBinding
.
instance
.
semanticsEnabled
,
isTrue
);
handle2
.
dispose
();
expect
(
status
.
single
,
isFalse
);
expect
(
SemanticsBinding
.
instance
.
semanticsEnabled
,
isFalse
);
},
semanticsEnabled:
false
);
testWidgets
(
'Listeners are called when semantics are turned on by platform'
,
(
WidgetTester
tester
)
async
{
expect
(
SemanticsBinding
.
instance
.
semanticsEnabled
,
isFalse
);
final
List
<
bool
>
status
=
<
bool
>[];
void
listener
()
{
status
.
add
(
SemanticsBinding
.
instance
.
semanticsEnabled
);
}
SemanticsBinding
.
instance
.
addSemanticsEnabledListener
(
listener
);
expect
(
SemanticsBinding
.
instance
.
semanticsEnabled
,
isFalse
);
tester
.
binding
.
platformDispatcher
.
semanticsEnabledTestValue
=
true
;
expect
(
status
.
single
,
isTrue
);
expect
(
SemanticsBinding
.
instance
.
semanticsEnabled
,
isTrue
);
status
.
clear
();
final
SemanticsHandle
handle
=
SemanticsBinding
.
instance
.
ensureSemantics
();
handle
.
dispose
();
expect
(
status
,
isEmpty
);
// Listener didn't fire.
expect
(
SemanticsBinding
.
instance
.
semanticsEnabled
,
isTrue
);
tester
.
binding
.
platformDispatcher
.
clearSemanticsEnabledTestValue
();
expect
(
status
.
single
,
isFalse
);
expect
(
SemanticsBinding
.
instance
.
semanticsEnabled
,
isFalse
);
},
semanticsEnabled:
false
);
testWidgets
(
'SemanticsBinding.ensureSemantics triggers creation of semantics owner.'
,
(
WidgetTester
tester
)
async
{
expect
(
SemanticsBinding
.
instance
.
semanticsEnabled
,
isFalse
);
expect
(
tester
.
binding
.
pipelineOwner
.
semanticsOwner
,
isNull
);
final
SemanticsHandle
handle
=
SemanticsBinding
.
instance
.
ensureSemantics
();
expect
(
SemanticsBinding
.
instance
.
semanticsEnabled
,
isTrue
);
expect
(
tester
.
binding
.
pipelineOwner
.
semanticsOwner
,
isNotNull
);
handle
.
dispose
();
expect
(
SemanticsBinding
.
instance
.
semanticsEnabled
,
isFalse
);
expect
(
tester
.
binding
.
pipelineOwner
.
semanticsOwner
,
isNull
);
},
semanticsEnabled:
false
);
}
packages/flutter/test/widgets/binding_cannot_schedule_frame_test.dart
View file @
b1b7284a
...
...
@@ -18,7 +18,9 @@ void main() {
// Enables the semantics should not schedule any frames if the root widget
// has not been attached.
binding
.
setSemanticsEnabled
(
true
);
expect
(
binding
.
semanticsEnabled
,
isFalse
);
binding
.
ensureSemantics
();
expect
(
binding
.
semanticsEnabled
,
isTrue
);
expect
(
SchedulerBinding
.
instance
.
framesEnabled
,
isFalse
);
expect
(
SchedulerBinding
.
instance
.
hasScheduledFrame
,
isFalse
);
...
...
packages/flutter_driver/lib/src/common/handler_factory.dart
View file @
b1b7284a
...
...
@@ -443,13 +443,13 @@ mixin CommandHandlerFactory {
}
SemanticsHandle
?
_semantics
;
bool
get
_semanticsIsEnabled
=>
RendererBinding
.
instance
.
pipelineOwner
.
semanticsOwner
!=
null
;
bool
get
_semanticsIsEnabled
=>
SemanticsBinding
.
instance
.
semanticsEnabled
;
Future
<
SetSemanticsResult
>
_setSemantics
(
Command
command
)
async
{
final
SetSemantics
setSemanticsCommand
=
command
as
SetSemantics
;
final
bool
semanticsWasEnabled
=
_semanticsIsEnabled
;
if
(
setSemanticsCommand
.
enabled
&&
_semantics
==
null
)
{
_semantics
=
RendererBinding
.
instance
.
pipelineOwner
.
ensureSemantics
();
_semantics
=
SemanticsBinding
.
instance
.
ensureSemantics
();
if
(!
semanticsWasEnabled
)
{
// wait for the first frame where semantics is enabled.
final
Completer
<
void
>
completer
=
Completer
<
void
>();
...
...
packages/flutter_test/lib/src/controller.dart
View file @
b1b7284a
...
...
@@ -72,7 +72,7 @@ class SemanticsController {
/// if no semantics are found or are not enabled.
SemanticsNode
find
(
Finder
finder
)
{
TestAsyncUtils
.
guardSync
();
if
(
_binding
.
pipelineOwner
.
semanticsOwner
==
null
)
{
if
(
!
_binding
.
semanticsEnabled
)
{
throw
StateError
(
'Semantics are not enabled.'
);
}
final
Iterable
<
Element
>
candidates
=
finder
.
evaluate
();
...
...
@@ -241,7 +241,7 @@ abstract class WidgetController {
/// use of the [Semantics] tree to determine the meaning of an application.
/// If semantics has been disabled for the test, this will throw a [StateError].
SemanticsController
get
semantics
{
if
(
binding
.
pipelineOwner
.
semanticsOwner
==
null
)
{
if
(
!
binding
.
semanticsEnabled
)
{
throw
StateError
(
'Semantics are not enabled. Enable them by passing '
'`semanticsEnabled: true` to `testWidgets`, or by manually creating a '
...
...
@@ -1491,7 +1491,7 @@ abstract class WidgetController {
///
/// The handle must be disposed at the end of the test.
SemanticsHandle
ensureSemantics
()
{
return
binding
.
pipelineOwner
.
ensureSemantics
();
return
binding
.
ensureSemantics
();
}
/// Given a widget `W` specified by [finder] and a [Scrollable] widget `S` in
...
...
packages/flutter_test/lib/src/finders.dart
View file @
b1b7284a
...
...
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import
'package:flutter/gestures.dart'
;
import
'package:flutter/material.dart'
show
Tooltip
;
import
'package:flutter/rendering.dart'
;
import
'package:flutter/widgets.dart'
;
import
'all_elements.dart'
;
...
...
@@ -435,7 +435,7 @@ class CommonFinders {
/// If the `skipOffstage` argument is true (the default), then this skips
/// nodes that are [Offstage] or that are from inactive [Route]s.
Finder
bySemanticsLabel
(
Pattern
label
,
{
bool
skipOffstage
=
true
})
{
if
(
WidgetsBinding
.
instance
.
pipelineOwner
.
semanticsOwner
==
null
)
{
if
(
!
SemanticsBinding
.
instance
.
semanticsEnabled
)
{
throw
StateError
(
'Semantics are not enabled. '
'Make sure to call tester.ensureSemantics() before using '
'this finder, and call dispose on its return value after.'
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment