diff --git a/src/io/flutter/devtools/DevToolsUrl.java b/src/io/flutter/devtools/DevToolsUrl.java index d7b6f5028a..aff9908b84 100644 --- a/src/io/flutter/devtools/DevToolsUrl.java +++ b/src/io/flutter/devtools/DevToolsUrl.java @@ -5,10 +5,12 @@ */ package io.flutter.devtools; +import com.intellij.openapi.application.ApplicationManager; import io.flutter.bazel.WorkspaceCache; import io.flutter.sdk.FlutterSdkUtil; import io.flutter.sdk.FlutterSdkVersion; import com.intellij.openapi.util.text.StringUtil; +import com.intellij.openapi.application.ApplicationInfo; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -19,6 +21,7 @@ import java.util.Objects; public class DevToolsUrl { + public static final String UNKNOWN_INTELLIJ_NAME = "IntelliJ - Unknown"; private String devToolsHost; private int devToolsPort; public String vmServiceUri; @@ -34,6 +37,7 @@ public class DevToolsUrl { private final boolean canUseMultiEmbed; public final DevToolsIdeFeature ideFeature; + private final String ideName; @NotNull private final DevToolsUtils devToolsUtils; @@ -50,6 +54,7 @@ public static class Builder { private @Nullable FlutterSdkVersion flutterSdkVersion; private WorkspaceCache workspaceCache; private DevToolsIdeFeature ideFeature; + private String ideName; private DevToolsUtils devToolsUtils; @@ -130,6 +135,12 @@ public Builder setFlutterSdkUtil(FlutterSdkUtil flutterSdkUtil) { return this; } + @NotNull + public Builder setIdeName(String ideName) { + this.ideName = ideName; + return this; + } + @NotNull public DevToolsUrl build() { if (devToolsUtils == null) { @@ -161,6 +172,7 @@ private DevToolsUrl(Builder builder) { this.flutterSdkVersion = builder.flutterSdkVersion; this.ideFeature = builder.ideFeature; this.sdkUtil = builder.flutterSdkUtil; + this.ideName = builder.ideName != null ? builder.ideName : getIdeName(); if (builder.workspaceCache != null && builder.workspaceCache.isBazel()) { this.canUseMultiEmbed = true; @@ -179,7 +191,10 @@ public String getUrlString() { final List params = new ArrayList<>(); String ideValue = sdkUtil.getFlutterHostEnvValue(); - params.add("ide=" + (ideValue == null ? "IntelliJPluginUnknown" : ideValue)); + String ideParamValue = ideValue == null ? UNKNOWN_INTELLIJ_NAME : ideValue; + params.add("ide=" + URLEncoder.encode(ideParamValue, StandardCharsets.UTF_8)); + params.add("dashTool=intellij-plugins"); + params.add("dashIdeName=" + URLEncoder.encode(this.ideName, StandardCharsets.UTF_8)); if (colorHexCode != null) { params.add("backgroundColor=" + colorHexCode); } @@ -216,6 +231,20 @@ public String getUrlString() { + StringUtil.join(params, "&"); } + private @NotNull String getIdeName() { + if (ApplicationManager.getApplication() == null) { + return UNKNOWN_INTELLIJ_NAME; + } + ApplicationInfo appInfo = ApplicationInfo.getInstance(); + if (appInfo != null) { + String versionName = appInfo.getVersionName(); + if (versionName != null) { + return versionName; + } + } + return UNKNOWN_INTELLIJ_NAME; + } + public boolean maybeUpdateColor() { final String newColor = devToolsUtils.getColorHexCode(); if (Objects.equals(colorHexCode, newColor)) { diff --git a/testSrc/unit/io/flutter/devtools/DevToolsUrlTest.java b/testSrc/unit/io/flutter/devtools/DevToolsUrlTest.java new file mode 100644 index 0000000000..6209a8fc4d --- /dev/null +++ b/testSrc/unit/io/flutter/devtools/DevToolsUrlTest.java @@ -0,0 +1,44 @@ +/* + * Copyright 2026 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; + +import io.flutter.sdk.FlutterSdkUtil; +import org.junit.Test; + +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +import static org.junit.Assert.assertTrue; + +public class DevToolsUrlTest { + + @Test + public void testGetUrlString() { + DevToolsUrl.Builder builder = new DevToolsUrl.Builder() + .setDevToolsHost("127.0.0.1") + .setDevToolsPort(9100) + .setVmServiceUri("http://127.0.0.1:12345/abc=") + .setIdeName("Test IDE Name"); + + // Mock FlutterSdkUtil to avoid calling real IntelliJ APIs which might fail in unit tests. + builder.setFlutterSdkUtil(new FlutterSdkUtil() { + @Override + public String getFlutterHostEnvValue() { + return "Test:IDE"; + } + }); + + DevToolsUrl devToolsUrl = builder.build(); + String url = devToolsUrl.getUrlString(); + + // Test:IDE encoded becomes Test%3AIDE + assertTrue(url.contains("ide=Test%3AIDE")); + assertTrue(url.contains("dashTool=intellij-plugins")); + + // Test IDE Name encoded becomes Test+IDE+Name + assertTrue(url.contains("dashIdeName=Test+IDE+Name")); + } +}