Some tools to dump other trees. (#9999)
diff --git a/packages/flutter/lib/src/rendering/binding.dart b/packages/flutter/lib/src/rendering/binding.dart index a3fb394..bfeef09 100644 --- a/packages/flutter/lib/src/rendering/binding.dart +++ b/packages/flutter/lib/src/rendering/binding.dart
@@ -68,6 +68,16 @@ callback: () { debugDumpRenderTree(); return debugPrintDone; } ); + registerSignalServiceExtension( + name: 'debugDumpLayerTree', + callback: () { debugDumpLayerTree(); return debugPrintDone; } + ); + + registerSignalServiceExtension( + name: 'debugDumpSemanticsTree', + callback: () { debugDumpSemanticsTree(); return debugPrintDone; } + ); + assert(() { // this service extension only works in checked mode registerBoolServiceExtension(
diff --git a/packages/flutter/test/foundation/service_extensions_test.dart b/packages/flutter/test/foundation/service_extensions_test.dart index bc40947..d94ccd2 100644 --- a/packages/flutter/test/foundation/service_extensions_test.dart +++ b/packages/flutter/test/foundation/service_extensions_test.dart
@@ -142,16 +142,52 @@ expect(result, <String, String>{}); expect(console, <Matcher>[ matches( + r'^' r'RenderView#[0-9]+\n' r' debug mode enabled - [a-zA-Z]+\n' r' window size: Size\(800\.0, 600\.0\) \(in physical pixels\)\n' r' device pixel ratio: 1\.0 \(physical pixels per logical pixel\)\n' r' configuration: Size\(800\.0, 600\.0\) at 1\.0x \(in logical pixels\)\n' + r'$' ), ]); console.clear(); }); + test('Service extensions - debugDumpLayerTree', () async { + Map<String, String> result; + + await binding.doFrame(); + result = await binding.testExtension('debugDumpLayerTree', <String, String>{}); + expect(result, <String, String>{}); + expect(console, <Matcher>[ + matches( + r'^' + r'TransformLayer#[0-9]+\n' + r' owner: RenderView#[0-9]+\n' + r' creator: RenderView\n' + r' offset: Offset\(0\.0, 0\.0\)\n' + r' transform:\n' + r' \[0] 1\.0,0\.0,0\.0,0\.0\n' + r' \[1] 0\.0,1\.0,0\.0,0\.0\n' + r' \[2] 0\.0,0\.0,1\.0,0\.0\n' + r' \[3] 0\.0,0\.0,0\.0,1\.0\n' + r'$' + ), + ]); + console.clear(); + }); + + test('Service extensions - debugDumpSemanticsTree', () async { + Map<String, String> result; + + await binding.doFrame(); + result = await binding.testExtension('debugDumpSemanticsTree', <String, String>{}); + expect(result, <String, String>{}); + expect(console, <String>['Semantics not collected.']); + console.clear(); + }); + test('Service extensions - debugPaint', () async { Map<String, String> result; Future<Map<String, String>> pendingResult; @@ -381,7 +417,7 @@ test('Service extensions - posttest', () async { // If you add a service extension... TEST IT! :-) // ...then increment this number. - expect(binding.extensions.length, 12); + expect(binding.extensions.length, 14); expect(console, isEmpty); debugPrint = debugPrintThrottled;
diff --git a/packages/flutter_tools/lib/src/resident_runner.dart b/packages/flutter_tools/lib/src/resident_runner.dart index e4f07d1..a568d62 100644 --- a/packages/flutter_tools/lib/src/resident_runner.dart +++ b/packages/flutter_tools/lib/src/resident_runner.dart
@@ -147,12 +147,22 @@ await view.uiIsolate.flutterDebugDumpRenderTree(); } + Future<Null> debugDumpLayerTree() async { + for (FlutterView view in views) + await view.uiIsolate.flutterDebugDumpLayerTree(); + } + + Future<Null> debugDumpSemanticsTree() async { + for (FlutterView view in views) + await view.uiIsolate.flutterDebugDumpSemanticsTree(); + } + Future<Null> toggleDebugPaintSizeEnabled() async { for (FlutterView view in views) await view.uiIsolate.flutterToggleDebugPaintSizeEnabled(); } - Future<String> togglePlatform({String from}) async { + Future<String> togglePlatform({ String from }) async { String to; switch (from) { case 'iOS': @@ -163,9 +173,8 @@ to = 'iOS'; break; } - for (FlutterView view in views) { + for (FlutterView view in views) await view.uiIsolate.flutterPlatformOverride(to); - } return to; } @@ -415,6 +424,18 @@ await device.debugDumpRenderTree(); } + Future<Null> _debugDumpLayerTree() async { + await refreshViews(); + for (FlutterDevice device in flutterDevices) + await device.debugDumpLayerTree(); + } + + Future<Null> _debugDumpSemanticsTree() async { + await refreshViews(); + for (FlutterDevice device in flutterDevices) + await device.debugDumpSemanticsTree(); + } + Future<Null> _debugToggleDebugPaintSizeEnabled() async { await refreshViews(); for (FlutterDevice device in flutterDevices) @@ -505,9 +526,8 @@ } Future<Null> connectToServiceProtocol({String viewFilter}) async { - if (!debuggingOptions.debuggingEnabled) { + if (!debuggingOptions.debuggingEnabled) return new Future<Null>.error('Error the service protocol is not enabled.'); - } bool viewFound = false; for (FlutterDevice device in flutterDevices) { @@ -564,12 +584,22 @@ await _debugDumpRenderTree(); return true; } + } else if (character == 'L') { + if (supportsServiceProtocol) { + await _debugDumpLayerTree(); + return true; + } + } else if (character == 'S') { + if (supportsServiceProtocol) { + await _debugDumpSemanticsTree(); + return true; + } } else if (lower == 'p') { if (supportsServiceProtocol && isRunningDebug) { await _debugToggleDebugPaintSizeEnabled(); return true; } - } else if (lower == 's') { + } else if (character == 's') { for (FlutterDevice device in flutterDevices) { if (device.device.supportsScreenshot) await _screenshot(device); @@ -656,16 +686,13 @@ final DependencyChecker dependencyChecker = new DependencyChecker(dartDependencySetBuilder, assetBundle); final String path = device.package.packagePath; - if (path == null) { + if (path == null) return true; - } final FileStat stat = fs.file(path).statSync(); - if (stat.type != FileSystemEntityType.FILE) { + if (stat.type != FileSystemEntityType.FILE) return true; - } - if (!fs.file(path).existsSync()) { + if (!fs.file(path).existsSync()) return true; - } final DateTime lastBuildTime = stat.modified; return dependencyChecker.check(lastBuildTime); } @@ -683,8 +710,9 @@ void printHelpDetails() { if (supportsServiceProtocol) { - printStatus('To dump the widget hierarchy of the app (debugDumpApp), press "w".'); + printStatus('You can dump the widget hierarchy of the app (debugDumpApp) by pressing "w".'); printStatus('To dump the rendering tree of the app (debugDumpRenderTree), press "t".'); + printStatus('For layers (debugDumpLayerTree), use "L"; accessibility (debugDumpSemantics), "S".'); if (isRunningDebug) { printStatus('To toggle the display of construction lines (debugPaintSizeEnabled), press "p".'); printStatus('To simulate different operating systems, (defaultTargetPlatform), press "o".');
diff --git a/packages/flutter_tools/lib/src/vmservice.dart b/packages/flutter_tools/lib/src/vmservice.dart index 9cf7675..fa3899b 100644 --- a/packages/flutter_tools/lib/src/vmservice.dart +++ b/packages/flutter_tools/lib/src/vmservice.dart
@@ -998,6 +998,14 @@ return invokeFlutterExtensionRpcRaw('ext.flutter.debugDumpRenderTree', timeout: kLongRequestTimeout); } + Future<Map<String, dynamic>> flutterDebugDumpLayerTree() { + return invokeFlutterExtensionRpcRaw('ext.flutter.debugDumpLayerTree', timeout: kLongRequestTimeout); + } + + Future<Map<String, dynamic>> flutterDebugDumpSemanticsTree() { + return invokeFlutterExtensionRpcRaw('ext.flutter.debugDumpSemanticsTree', timeout: kLongRequestTimeout); + } + Future<Map<String, dynamic>> flutterToggleDebugPaintSizeEnabled() async { Map<String, dynamic> state = await invokeFlutterExtensionRpcRaw('ext.flutter.debugPaint'); if (state != null && state.containsKey('enabled') && state['enabled'] is String) {