diff --git a/flutter-idea/src/io/flutter/devtools/DevToolsIdeFeature.java b/flutter-idea/src/io/flutter/devtools/DevToolsIdeFeature.java new file mode 100644 index 0000000000..7f9a044a04 --- /dev/null +++ b/flutter-idea/src/io/flutter/devtools/DevToolsIdeFeature.java @@ -0,0 +1,22 @@ +/* + * Copyright 2023 The Chromium Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +package io.flutter.devtools; + +/** + * This identifies from what feature DevTools is started. See https://github.com/flutter/flutter-intellij/issues/7100 for details. + */ +public enum DevToolsIdeFeature { + ON_DEBUG_AUTOMATIC("onDebugAutomatic"), + RUN_CONSOLE("runConsole"), + TOOL_WINDOW("toolWindow"), + TOOL_WINDOW_RELOAD("toolWindowReload"); + + public final String value; + + DevToolsIdeFeature(String value) { + this.value = value; + } +} diff --git a/flutter-idea/src/io/flutter/devtools/DevToolsUrl.java b/flutter-idea/src/io/flutter/devtools/DevToolsUrl.java index ac6bd5743a..3d77000a4f 100644 --- a/flutter-idea/src/io/flutter/devtools/DevToolsUrl.java +++ b/flutter-idea/src/io/flutter/devtools/DevToolsUrl.java @@ -30,6 +30,8 @@ public class DevToolsUrl { private final boolean canUseDevToolsPathUrl; + public final DevToolsIdeFeature ideFeature; + public DevToolsUrl(String devtoolsHost, int devtoolsPort, String vmServiceUri, @@ -38,8 +40,9 @@ public DevToolsUrl(String devtoolsHost, String colorHexCode, Float fontSize, @Nullable FlutterSdkVersion flutterSdkVersion, - WorkspaceCache workspaceCache) { - this(devtoolsHost, devtoolsPort, vmServiceUri, page, embed, colorHexCode, fontSize, flutterSdkVersion, workspaceCache, new FlutterSdkUtil()); + WorkspaceCache workspaceCache, + DevToolsIdeFeature ideFeature) { + this(devtoolsHost, devtoolsPort, vmServiceUri, page, embed, colorHexCode, fontSize, flutterSdkVersion, workspaceCache, ideFeature, new FlutterSdkUtil()); } @@ -52,6 +55,7 @@ public DevToolsUrl(String devtoolsHost, Float fontSize, FlutterSdkVersion flutterSdkVersion, WorkspaceCache workspaceCache, + DevToolsIdeFeature ideFeature, FlutterSdkUtil flutterSdkUtil) { this.devtoolsHost = devtoolsHost; this.devtoolsPort = devtoolsPort; @@ -61,6 +65,7 @@ public DevToolsUrl(String devtoolsHost, this.colorHexCode = colorHexCode; this.fontSize = fontSize; this.flutterSdkVersion = flutterSdkVersion; + this.ideFeature = ideFeature; this.sdkUtil = flutterSdkUtil; if (workspaceCache != null && workspaceCache.isBazel()) { @@ -90,12 +95,13 @@ public String getUrlString() { if (fontSize != null) { params.add("fontSize=" + fontSize); } - + if (ideFeature != null) { + params.add("ideFeature=" + ideFeature.value); + } if (vmServiceUri != null) { final String urlParam = URLEncoder.encode(vmServiceUri, StandardCharsets.UTF_8); params.add("uri=" + urlParam); } - if (widgetId != null) { params.add("inspectorRef=" + widgetId); } diff --git a/flutter-idea/src/io/flutter/performance/FlutterPerformanceView.java b/flutter-idea/src/io/flutter/performance/FlutterPerformanceView.java index 1ab0ab5120..24a7d69fac 100644 --- a/flutter-idea/src/io/flutter/performance/FlutterPerformanceView.java +++ b/flutter-idea/src/io/flutter/performance/FlutterPerformanceView.java @@ -218,7 +218,7 @@ private void addPerformanceViewContent(FlutterApp app, ToolWindow toolWindow) { FlutterSdk flutterSdk = FlutterSdk.getFlutterSdk(app.getProject()); BrowserLauncher.getInstance().browse( - (new DevToolsUrl(instance.host, instance.port, app.getConnector().getBrowserUrl(), null, false, null, null, flutterSdk == null ? null : flutterSdk.getVersion(), WorkspaceCache.getInstance(app.getProject()))).getUrlString(), + (new DevToolsUrl(instance.host, instance.port, app.getConnector().getBrowserUrl(), null, false, null, null, flutterSdk == null ? null : flutterSdk.getVersion(), WorkspaceCache.getInstance(app.getProject()), null)).getUrlString(), null ); }); diff --git a/flutter-idea/src/io/flutter/run/OpenDevToolsAction.java b/flutter-idea/src/io/flutter/run/OpenDevToolsAction.java index 27281856ff..416a11fd1b 100644 --- a/flutter-idea/src/io/flutter/run/OpenDevToolsAction.java +++ b/flutter-idea/src/io/flutter/run/OpenDevToolsAction.java @@ -15,6 +15,7 @@ import io.flutter.FlutterInitializer; import io.flutter.ObservatoryConnector; import io.flutter.bazel.WorkspaceCache; +import io.flutter.devtools.DevToolsIdeFeature; import io.flutter.devtools.DevToolsUrl; import io.flutter.run.daemon.DevToolsService; import io.flutter.run.daemon.FlutterApp; @@ -79,7 +80,7 @@ public void actionPerformed(@NotNull final AnActionEvent event) { FlutterSdk flutterSdk = FlutterSdk.getFlutterSdk(project); BrowserLauncher.getInstance().browse( - (new DevToolsUrl(instance.host, instance.port, serviceUrl, null, false, null, null, flutterSdk == null ? null : flutterSdk.getVersion(), WorkspaceCache.getInstance(project)).getUrlString()), + (new DevToolsUrl(instance.host, instance.port, serviceUrl, null, false, null, null, flutterSdk == null ? null : flutterSdk.getVersion(), WorkspaceCache.getInstance(project), DevToolsIdeFeature.RUN_CONSOLE).getUrlString()), null ); }); diff --git a/flutter-idea/src/io/flutter/view/FlutterView.java b/flutter-idea/src/io/flutter/view/FlutterView.java index 9b54f15124..fd576cc697 100644 --- a/flutter-idea/src/io/flutter/view/FlutterView.java +++ b/flutter-idea/src/io/flutter/view/FlutterView.java @@ -51,6 +51,7 @@ import io.flutter.FlutterInitializer; import io.flutter.FlutterUtils; import io.flutter.bazel.WorkspaceCache; +import io.flutter.devtools.DevToolsIdeFeature; import io.flutter.devtools.DevToolsUrl; import io.flutter.inspector.DiagnosticsNode; import io.flutter.inspector.InspectorGroupManagerService; @@ -75,6 +76,7 @@ import java.util.List; import java.util.*; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.atomic.AtomicReference; @com.intellij.openapi.components.State( name = "FlutterView", @@ -243,6 +245,7 @@ private void addBrowserInspectorViewContent(FlutterApp app, @Nullable InspectorService inspectorService, ToolWindow toolWindow, boolean isEmbedded, + DevToolsIdeFeature ideFeature, DevToolsInstance devToolsInstance) { assert(SwingUtilities.isEventDispatchThread()); @@ -275,7 +278,8 @@ private void addBrowserInspectorViewContent(FlutterApp app, color, UIUtil.getFontSize(UIUtil.FontSize.NORMAL), flutterSdkVersion, - WorkspaceCache.getInstance(app.getProject()) + WorkspaceCache.getInstance(app.getProject()), + ideFeature ); //noinspection CodeBlock2Expr @@ -284,7 +288,7 @@ private void addBrowserInspectorViewContent(FlutterApp app, // If the embedded browser doesn't work, offer a link to open in the regular browser. final List inputs = Arrays.asList( new LabelInput("The embedded browser failed to load. Error: " + error), - openDevToolsLabel(app, inspectorService, toolWindow) + openDevToolsLabel(app, inspectorService, toolWindow, ideFeature) ); presentClickableLabel(toolWindow, inputs); })); @@ -304,7 +308,7 @@ private void addBrowserInspectorViewContent(FlutterApp app, } else { BrowserLauncher.getInstance().browse( (new DevToolsUrl(devToolsInstance.host, devToolsInstance.port, browserUrl, "inspector", false, null, null, - flutterSdkVersion, WorkspaceCache.getInstance(app.getProject())).getUrlString()), + flutterSdkVersion, WorkspaceCache.getInstance(app.getProject()), ideFeature).getUrlString()), null ); presentLabel(toolWindow, "DevTools inspector has been opened in the browser."); @@ -486,19 +490,15 @@ public void debugActive(@NotNull FlutterViewMessages.FlutterDebugEvent event) { } } - protected void handleJxBrowserInstalled(FlutterApp app, InspectorService inspectorService, ToolWindow toolWindow) { - presentDevTools(app, inspectorService, toolWindow, true); - } - - private void presentDevTools(FlutterApp app, InspectorService inspectorService, ToolWindow toolWindow, boolean isEmbedded) { + private void presentDevTools(FlutterApp app, InspectorService inspectorService, ToolWindow toolWindow, boolean isEmbedded, DevToolsIdeFeature ideFeature) { verifyEventDispatchThread(); devToolsInstallCount += 1; presentLabel(toolWindow, getInstallingDevtoolsLabel()); - openInspectorWithDevTools(app, inspectorService, toolWindow, isEmbedded); + openInspectorWithDevTools(app, inspectorService, toolWindow, isEmbedded, ideFeature); - setUpToolWindowListener(app, inspectorService, toolWindow, isEmbedded); + setUpToolWindowListener(app, inspectorService, toolWindow, isEmbedded, ideFeature); } @VisibleForTesting @@ -507,14 +507,14 @@ protected void verifyEventDispatchThread() { } @VisibleForTesting - protected void setUpToolWindowListener(FlutterApp app, InspectorService inspectorService, ToolWindow toolWindow, boolean isEmbedded) { + protected void setUpToolWindowListener(FlutterApp app, InspectorService inspectorService, ToolWindow toolWindow, boolean isEmbedded, DevToolsIdeFeature ideFeature) { if (this.toolWindowListener == null) { this.toolWindowListener = new FlutterViewToolWindowManagerListener(myProject, toolWindow); } this.toolWindowListener.updateOnWindowOpen(() -> { devToolsInstallCount += 1; presentLabel(toolWindow, getInstallingDevtoolsLabel()); - openInspectorWithDevTools(app, inspectorService, toolWindow, isEmbedded, true); + openInspectorWithDevTools(app, inspectorService, toolWindow, isEmbedded, ideFeature, true); }); } @@ -524,14 +524,15 @@ private String getInstallingDevtoolsLabel() { } @VisibleForTesting - protected void openInspectorWithDevTools(FlutterApp app, InspectorService inspectorService, ToolWindow toolWindow, boolean isEmbedded) { - openInspectorWithDevTools(app, inspectorService, toolWindow, isEmbedded, false); + protected void openInspectorWithDevTools(FlutterApp app, InspectorService inspectorService, ToolWindow toolWindow, boolean isEmbedded, DevToolsIdeFeature ideFeature) { + openInspectorWithDevTools(app, inspectorService, toolWindow, isEmbedded, ideFeature, false); } private void openInspectorWithDevTools(FlutterApp app, InspectorService inspectorService, ToolWindow toolWindow, boolean isEmbedded, + DevToolsIdeFeature ideFeature, boolean forceDevToolsRestart) { AsyncUtils.whenCompleteUiThread( forceDevToolsRestart @@ -555,14 +556,14 @@ private void openInspectorWithDevTools(FlutterApp app, return; } - addBrowserInspectorViewContent(app, inspectorService, toolWindow, isEmbedded, instance); + addBrowserInspectorViewContent(app, inspectorService, toolWindow, isEmbedded, ideFeature, instance); } ); } - private LabelInput openDevToolsLabel(FlutterApp app, InspectorService inspectorService, ToolWindow toolWindow) { + private LabelInput openDevToolsLabel(FlutterApp app, InspectorService inspectorService, ToolWindow toolWindow, DevToolsIdeFeature ideFeature) { return new LabelInput("Open DevTools in the browser?", (linkLabel, data) -> { - presentDevTools(app, inspectorService, toolWindow, false); + presentDevTools(app, inspectorService, toolWindow, false, ideFeature); }); } @@ -595,16 +596,6 @@ protected void presentClickableLabel(ToolWindow toolWindow, List lab replacePanelLabel(toolWindow, center); } - protected void presentOpenDevToolsOptionWithMessage(FlutterApp app, - InspectorService inspectorService, - ToolWindow toolWindow, - String message) { - final List inputs = new ArrayList<>(); - inputs.add(new LabelInput(message)); - inputs.add(openDevToolsLabel(app, inspectorService, toolWindow)); - presentClickableLabel(toolWindow, inputs); - } - private void replacePanelLabel(ToolWindow toolWindow, JComponent label) { ApplicationManager.getApplication().invokeLater(() -> { final ContentManager contentManager = toolWindow.getContentManager(); @@ -631,12 +622,13 @@ private void debugActiveHelper(FlutterApp app, @Nullable InspectorService inspec return; } + AtomicReference ideFeature = new AtomicReference<>(null); if (toolWindow.isAvailable()) { - updateToolWindowVisibility(toolWindow); + ideFeature.set(updateToolWindowVisibility(toolWindow)); } else { toolWindow.setAvailable(true, () -> { - updateToolWindowVisibility(toolWindow); + ideFeature.set(updateToolWindowVisibility(toolWindow)); }); } @@ -649,7 +641,7 @@ private void debugActiveHelper(FlutterApp app, @Nullable InspectorService inspec toolWindow.setIcon(ExecutionUtil.getLiveIndicator(FlutterIcons.Flutter_13)); if (toolWindow.isVisible()) { - displayEmbeddedBrowser(app, inspectorService, toolWindow); + displayEmbeddedBrowser(app, inspectorService, toolWindow, ideFeature.get()); } else { if (toolWindowListener == null) { @@ -657,13 +649,13 @@ private void debugActiveHelper(FlutterApp app, @Nullable InspectorService inspec } // If the window isn't visible yet, only executed embedded browser steps when it becomes visible. toolWindowListener.updateOnWindowFirstVisible(() -> { - displayEmbeddedBrowser(app, inspectorService, toolWindow); + displayEmbeddedBrowser(app, inspectorService, toolWindow, DevToolsIdeFeature.TOOL_WINDOW); }); } } - private void displayEmbeddedBrowser(FlutterApp app, InspectorService inspectorService, ToolWindow toolWindow) { - presentDevTools(app, inspectorService, toolWindow, true); + private void displayEmbeddedBrowser(FlutterApp app, InspectorService inspectorService, ToolWindow toolWindow, DevToolsIdeFeature ideFeature) { + presentDevTools(app, inspectorService, toolWindow, true, ideFeature); } private void updateForEmptyContent(ToolWindow toolWindow) { @@ -765,14 +757,18 @@ private void onAppChanged(FlutterApp app) { } } - private void updateToolWindowVisibility(ToolWindow flutterToolWindow) { + // Returns true if the toolWindow was initially closed but opened automatically on app launch. + private DevToolsIdeFeature updateToolWindowVisibility(ToolWindow flutterToolWindow) { if (flutterToolWindow.isVisible()) { - return; + return DevToolsIdeFeature.TOOL_WINDOW_RELOAD; } if (FlutterSettings.getInstance().isOpenInspectorOnAppLaunch()) { flutterToolWindow.show(null); + return DevToolsIdeFeature.ON_DEBUG_AUTOMATIC; } + + return null; } } @@ -802,7 +798,7 @@ public void perform(AnActionEvent event) { FlutterSdk flutterSdk = FlutterSdk.getFlutterSdk(app.getProject()); BrowserLauncher.getInstance().browse( - (new DevToolsUrl(instance.host, instance.port, urlString, null, false, null, null, flutterSdk == null ? null : flutterSdk.getVersion(), WorkspaceCache.getInstance(app.getProject())).getUrlString()), + (new DevToolsUrl(instance.host, instance.port, urlString, null, false, null, null, flutterSdk == null ? null : flutterSdk.getVersion(), WorkspaceCache.getInstance(app.getProject()), null).getUrlString()), null ); }); diff --git a/flutter-idea/testSrc/unit/io/flutter/devtools/DevToolsUrlTest.java b/flutter-idea/testSrc/unit/io/flutter/devtools/DevToolsUrlTest.java index 8f1460f473..68b7f1cc9f 100644 --- a/flutter-idea/testSrc/unit/io/flutter/devtools/DevToolsUrlTest.java +++ b/flutter-idea/testSrc/unit/io/flutter/devtools/DevToolsUrlTest.java @@ -29,55 +29,60 @@ public void testGetUrlString() { FlutterSdkVersion newVersion = new FlutterSdkVersion("3.3.0"); assertEquals( "http://127.0.0.1:9100/timeline?ide=IntelliJ-IDEA&uri=http%3A%2F%2F127.0.0.1%3A50224%2FWTFTYus3IPU%3D%2F", - (new DevToolsUrl(devtoolsHost, devtoolsPort, serviceProtocolUri, page, false, null, null, newVersion, notBazelWorkspaceCache, mockSdkUtil)).getUrlString() + (new DevToolsUrl(devtoolsHost, devtoolsPort, serviceProtocolUri, page, false, null, null, newVersion, notBazelWorkspaceCache, null, mockSdkUtil)).getUrlString() ); assertEquals( "http://127.0.0.1:9100/timeline?ide=IntelliJ-IDEA&embed=true&uri=http%3A%2F%2F127.0.0.1%3A50224%2FWTFTYus3IPU%3D%2F", - (new DevToolsUrl(devtoolsHost, devtoolsPort, serviceProtocolUri, page, true, null, null, newVersion, notBazelWorkspaceCache, mockSdkUtil)).getUrlString() + (new DevToolsUrl(devtoolsHost, devtoolsPort, serviceProtocolUri, page, true, null, null, newVersion, notBazelWorkspaceCache, null, mockSdkUtil)).getUrlString() ); assertEquals( "http://127.0.0.1:9100/?ide=IntelliJ-IDEA", - (new DevToolsUrl(devtoolsHost, devtoolsPort, null, null, false, null, null, newVersion, notBazelWorkspaceCache, mockSdkUtil).getUrlString()) + (new DevToolsUrl(devtoolsHost, devtoolsPort, null, null, false, null, null, newVersion, notBazelWorkspaceCache, null, mockSdkUtil).getUrlString()) ); assertEquals( "http://127.0.0.1:9100/timeline?ide=IntelliJ-IDEA&backgroundColor=ffffff&uri=http%3A%2F%2F127.0.0.1%3A50224%2FWTFTYus3IPU%3D%2F", - (new DevToolsUrl(devtoolsHost, devtoolsPort, serviceProtocolUri, page, false, "ffffff", null, newVersion, notBazelWorkspaceCache, mockSdkUtil).getUrlString()) + (new DevToolsUrl(devtoolsHost, devtoolsPort, serviceProtocolUri, page, false, "ffffff", null, newVersion, notBazelWorkspaceCache, null, mockSdkUtil).getUrlString()) ); assertEquals( "http://127.0.0.1:9100/timeline?ide=IntelliJ-IDEA&backgroundColor=ffffff&fontSize=12.0&uri=http%3A%2F%2F127.0.0.1%3A50224%2FWTFTYus3IPU%3D%2F", - (new DevToolsUrl(devtoolsHost, devtoolsPort, serviceProtocolUri, page, false, "ffffff", 12.0f, newVersion, notBazelWorkspaceCache, mockSdkUtil).getUrlString()) + (new DevToolsUrl(devtoolsHost, devtoolsPort, serviceProtocolUri, page, false, "ffffff", 12.0f, newVersion, notBazelWorkspaceCache, null, mockSdkUtil).getUrlString()) ); when(mockSdkUtil.getFlutterHostEnvValue()).thenReturn("Android-Studio"); assertEquals( "http://127.0.0.1:9100/timeline?ide=Android-Studio&uri=http%3A%2F%2F127.0.0.1%3A50224%2FWTFTYus3IPU%3D%2F", - (new DevToolsUrl(devtoolsHost, devtoolsPort, serviceProtocolUri, page, false, null, null, newVersion, notBazelWorkspaceCache, mockSdkUtil).getUrlString()) + (new DevToolsUrl(devtoolsHost, devtoolsPort, serviceProtocolUri, page, false, null, null, newVersion, notBazelWorkspaceCache, null, mockSdkUtil).getUrlString()) ); assertEquals( "http://127.0.0.1:9100/timeline?ide=Android-Studio&backgroundColor=3c3f41&uri=http%3A%2F%2F127.0.0.1%3A50224%2FWTFTYus3IPU%3D%2F", - (new DevToolsUrl(devtoolsHost, devtoolsPort, serviceProtocolUri, page, false, "3c3f41", null, newVersion, notBazelWorkspaceCache, mockSdkUtil).getUrlString()) + (new DevToolsUrl(devtoolsHost, devtoolsPort, serviceProtocolUri, page, false, "3c3f41", null, newVersion, notBazelWorkspaceCache, null, mockSdkUtil).getUrlString()) ); FlutterSdkVersion oldVersion = new FlutterSdkVersion("3.0.0"); assertEquals( "http://127.0.0.1:9100/#/?ide=Android-Studio&page=timeline&uri=http%3A%2F%2F127.0.0.1%3A50224%2FWTFTYus3IPU%3D%2F", - (new DevToolsUrl(devtoolsHost, devtoolsPort, serviceProtocolUri, page, false, null, null, oldVersion, notBazelWorkspaceCache, mockSdkUtil)).getUrlString() + (new DevToolsUrl(devtoolsHost, devtoolsPort, serviceProtocolUri, page, false, null, null, oldVersion, notBazelWorkspaceCache, null, mockSdkUtil)).getUrlString() ); assertEquals( "http://127.0.0.1:9100/#/?ide=Android-Studio&page=timeline&uri=http%3A%2F%2F127.0.0.1%3A50224%2FWTFTYus3IPU%3D%2F", - (new DevToolsUrl(devtoolsHost, devtoolsPort, serviceProtocolUri, page, false, null, null, null, notBazelWorkspaceCache, mockSdkUtil)).getUrlString() + (new DevToolsUrl(devtoolsHost, devtoolsPort, serviceProtocolUri, page, false, null, null, null, notBazelWorkspaceCache, null, mockSdkUtil)).getUrlString() ); assertEquals( "http://127.0.0.1:9100/timeline?ide=Android-Studio&uri=http%3A%2F%2F127.0.0.1%3A50224%2FWTFTYus3IPU%3D%2F", - (new DevToolsUrl(devtoolsHost, devtoolsPort, serviceProtocolUri, page, false, null, null, null, bazelWorkspaceCache, mockSdkUtil)).getUrlString() + (new DevToolsUrl(devtoolsHost, devtoolsPort, serviceProtocolUri, page, false, null, null, null, bazelWorkspaceCache, null, mockSdkUtil)).getUrlString() + ); + + assertEquals( + "http://127.0.0.1:9100/timeline?ide=Android-Studio&ideFeature=toolWindow&uri=http%3A%2F%2F127.0.0.1%3A50224%2FWTFTYus3IPU%3D%2F", + (new DevToolsUrl(devtoolsHost, devtoolsPort, serviceProtocolUri, page, false, null, null, null, bazelWorkspaceCache, DevToolsIdeFeature.TOOL_WINDOW, mockSdkUtil)).getUrlString() ); } } \ No newline at end of file