Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions packages/devtools_app/lib/src/shared/framework/screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ library;

import 'package:collection/collection.dart';
import 'package:devtools_app_shared/service.dart';
import 'package:devtools_app_shared/service_extensions.dart' as extensions;
import 'package:devtools_app_shared/shared.dart';
import 'package:devtools_app_shared/ui.dart';
import 'package:flutter/foundation.dart';
Expand Down Expand Up @@ -558,6 +559,18 @@ abstract class Screen {
return (show: false, disabledReason: ScreenDisabledReason.requiresFlutter);
}
if (screen.requiresDebugBuild && connectedApp.isProfileBuildNow == true) {
// Build mode is inferred from expression evaluation. A debug-only service
// extension identifies a debug app whose expressions could not be compiled,
// for example when connecting without Flutter Tools.
if (connectedApp.isFlutterAppNow == true &&
serviceManager.serviceExtensionManager.isServiceExtensionAvailable(
extensions.debugAllowBanner.extension,
)) {
return (
show: false,
disabledReason: ScreenDisabledReason.expressionEvaluationUnavailable,
);
}
_log.finest('screen requires debug build: returning false');
return (
show: false,
Expand Down Expand Up @@ -598,6 +611,12 @@ enum ScreenDisabledReason {
requiresDartLibrary(null),
requiresDartVm('requires the Dart VM, but it is not available.'),
requiresDebugBuild('only supports debug builds.'),

/// A Flutter debug app was detected, but expression evaluation failed.
expressionEvaluationUnavailable(
'could not evaluate expressions. Try running "flutter attach" and '
'reconnecting DevTools.',
),
requiresFlutter('only supports Flutter applications.'),
requiresAdvancedDeveloperMode(
'only works when Advanced Developer Mode is enabled',
Expand Down
4 changes: 4 additions & 0 deletions packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ To learn more about DevTools, check out the

## General updates

* Added guidance to run "flutter attach" when a Flutter debug app cannot
evaluate expressions and a debug-only screen is unavailable.
[#4091](https://github.com/flutter/devtools/issues/4091)

TODO: Remove this section if there are not any updates.

* Improved the readability of ANSI-colored text in the console and logging
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import 'package:devtools_app/devtools_app.dart';
import 'package:devtools_app/src/shared/framework/framework_controller.dart';
import 'package:devtools_app_shared/service_extensions.dart' as extensions;
import 'package:devtools_app_shared/utils.dart';
import 'package:devtools_shared/devtools_shared.dart';
import 'package:devtools_test/devtools_test.dart';
Expand Down Expand Up @@ -166,6 +167,37 @@ void main() {
);
});

testWidgets('explain unavailable evaluation in an unattached debug app', (
WidgetTester tester,
) async {
// Failed expression evaluation makes the build-mode heuristic report
// profile mode, even though debug-only extensions are registered.
setupMockConnectedApp(flutter: true, debugMode: false);
final extensionManager =
fakeServiceConnection.serviceManager.serviceExtensionManager;
// The extension may still be pending its first frame.
await extensionManager.fakeAddServiceExtension(
extensions.debugAllowBanner.extension,
);

final result = shouldShowScreen(DebuggerScreen());
expect(result.show, isFalse);
expect(result.disabledReason?.message, contains('flutter attach'));
expect(
result.disabledReason?.message,
isNot(contains('only supports debug')),
);
});

testWidgets('keep the profile-build explanation for a real profile app', (
WidgetTester tester,
) async {
setupMockConnectedApp(flutter: true, debugMode: false);
final result = shouldShowScreen(DebuggerScreen());
expect(result.show, isFalse);
expect(result.disabledReason?.message, 'only supports debug builds.');
});

testWidgets('are correct for Flutter (non-web) profile app', (
WidgetTester tester,
) async {
Expand Down
Loading