Commit ca5e1f3f authored by Jason Simmons's avatar Jason Simmons Committed by GitHub

In the semantics tree, do not detach a child if it has already been assigned a new parent (#6773)

Fixes https://github.com/flutter/flutter/issues/6690

Also add a version of the Gallery smoke test that enables semantics
parent 546cef52
...@@ -5,9 +5,10 @@ ...@@ -5,9 +5,10 @@
import 'dart:collection' show LinkedHashSet; import 'dart:collection' show LinkedHashSet;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:flutter_gallery/gallery/item.dart' show GalleryItem, kAllGalleryItems; import 'package:flutter_gallery/gallery/item.dart' show GalleryItem, kAllGalleryItems;
import 'package:flutter_gallery/main.dart' as flutter_gallery_main; import 'package:flutter_gallery/gallery/app.dart' show GalleryApp;
const String kCaption = 'Flutter Gallery'; const String kCaption = 'Flutter Gallery';
...@@ -47,10 +48,8 @@ Future<Null> smokeDemo(WidgetTester tester, String routeName) async { ...@@ -47,10 +48,8 @@ Future<Null> smokeDemo(WidgetTester tester, String routeName) async {
return null; return null;
} }
void main() { Future<Null> runSmokeTest(WidgetTester tester) async {
testWidgets('Flutter Gallery app smoke test', (WidgetTester tester) async { await tester.pumpWidget(new GalleryApp());
flutter_gallery_main
.main(); // builds the app and schedules a frame but doesn't trigger one
await tester.pump(); // see https://github.com/flutter/flutter/issues/1865 await tester.pump(); // see https://github.com/flutter/flutter/issues/1865
await tester.pump(); // triggers a frame await tester.pump(); // triggers a frame
...@@ -90,5 +89,14 @@ void main() { ...@@ -90,5 +89,14 @@ void main() {
await tester.tap(find.text('Light')); await tester.tap(find.text('Light'));
await tester.pump(); await tester.pump();
await tester.pump(const Duration(seconds: 1)); // Wait until it's changed. await tester.pump(const Duration(seconds: 1)); // Wait until it's changed.
}
void main() {
testWidgets('Flutter Gallery app smoke test', runSmokeTest);
testWidgets('Flutter Gallery app smoke test', (WidgetTester tester) async {
RendererBinding.instance.setSemanticsEnabled(true);
await runSmokeTest(tester);
RendererBinding.instance.setSemanticsEnabled(false);
}); });
} }
...@@ -138,7 +138,11 @@ abstract class RendererBinding extends BindingBase implements SchedulerBinding, ...@@ -138,7 +138,11 @@ abstract class RendererBinding extends BindingBase implements SchedulerBinding,
SemanticsHandle _semanticsHandle; SemanticsHandle _semanticsHandle;
void _handleSemanticsEnabledChanged() { void _handleSemanticsEnabledChanged() {
if (ui.window.semanticsEnabled) { setSemanticsEnabled(ui.window.semanticsEnabled);
}
void setSemanticsEnabled(bool enabled) {
if (enabled) {
_semanticsHandle ??= _pipelineOwner.ensureSemantics(); _semanticsHandle ??= _pipelineOwner.ensureSemantics();
} else { } else {
_semanticsHandle?.dispose(); _semanticsHandle?.dispose();
......
...@@ -372,6 +372,7 @@ class SemanticsNode extends AbstractNode { ...@@ -372,6 +372,7 @@ class SemanticsNode extends AbstractNode {
/// child list for the given frame at once instead of needing to process the /// child list for the given frame at once instead of needing to process the
/// changes incrementally as new children are compiled. /// changes incrementally as new children are compiled.
void finalizeChildren() { void finalizeChildren() {
// The goal of this function is updating sawChange.
if (_children != null) { if (_children != null) {
for (SemanticsNode child in _children) for (SemanticsNode child in _children)
child._dead = true; child._dead = true;
...@@ -473,10 +474,14 @@ class SemanticsNode extends AbstractNode { ...@@ -473,10 +474,14 @@ class SemanticsNode extends AbstractNode {
owner._detachedNodes.add(this); owner._detachedNodes.add(this);
super.detach(); super.detach();
if (_children != null) { if (_children != null) {
for (SemanticsNode child in _children) for (SemanticsNode child in _children) {
// The list of children may be stale and may contain nodes that have
// been assigned to a different parent.
if (child.parent == this)
child.detach(); child.detach();
} }
} }
}
bool _dirty = false; bool _dirty = false;
void _markDirty() { void _markDirty() {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment