Skip to content

Commit be8bcce

Browse files
authored
Fix device labels missing from run tabs on IntelliJ 2025.3+ (#8796)
## Summary - Fix `IllegalAccessException` that silently prevents device names from appearing in Run/Debug tab titles on IntelliJ 2025.3 (Android Studio Panda) - Use `RunContentDescriptor.setDisplayName()` API instead of reaching into a private field's internal type Fixes #8795 ## Problem In IntelliJ 2025.3, the `myDisplayNameView` field on `RunContentDescriptor` changed from `MutableReactiveProperty` (a public class) to `MutableStateFlow` (whose runtime class `StateFlowImpl` is package-private). The existing reflection code calls `Method.invoke()` on the `setValue` method found via `getMethod()`, which throws `IllegalAccessException` when the declaring class is not accessible — even though the method itself is public. The exception is caught silently, so run tabs show "main.dart" instead of "main.dart (macOS)". Regression introduced by [JetBrains/intellij-community@`aaa88849ba4c`](JetBrains/intellij-community@aaa8884) (Jul 14, 2025). ## Fix Replace the field-level reflection (`getDeclaredField("myDisplayNameView")` → `getMethod("setValue")` → `invoke()`) with a call to `RunContentDescriptor.setDisplayName()`, an existing protected method on `RunContentDescriptor`. This calls a stable API method on a public class rather than depending on the internal type of a private field. An alternative minimal fix would be to add `setValueMethod.setAccessible(true)` before the existing `invoke()` call, but calling a stable API method on a public class is more resilient than depending on the internal type of a private field. ## Before & After ### Before fix <img width="293" height="116" alt="Screenshot 2026-02-15 at 2 53 56 PM" src="https://github.com/user-attachments/assets/61f7d727-871a-438b-9735-7f51fc5a743e" /> ### After fix: <img width="321" height="128" alt="Screenshot 2026-02-15 at 2 52 38 PM" src="https://github.com/user-attachments/assets/efa559a1-1fa2-4d37-a94a-bdf9b544bf67" /> --- - [x] I've reviewed the contributor guide and applied the relevant portions to this PR. <details> <summary>Contribution guidelines:</summary><br> - See our [contributor guide](https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview) for general expectations for PRs. - Larger or significant changes should be discussed in an issue before creating a PR. - Dart contributions to our repos should follow the [Dart style guide](https://dart.dev/guides/language/effective-dart) and use `dart format`. - Java and Kotlin contributions should strive to follow Java and Kotlin best practices ([discussion](#8098)). </details>
1 parent 69ec556 commit be8bcce

1 file changed

Lines changed: 5 additions & 10 deletions

File tree

src/io/flutter/run/LaunchState.java

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@
5555
import org.jetbrains.annotations.NotNull;
5656
import org.jetbrains.annotations.Nullable;
5757

58-
import java.lang.reflect.Field;
5958
import java.lang.reflect.InvocationTargetException;
6059
import java.lang.reflect.Method;
6160
import java.util.ArrayList;
@@ -171,16 +170,12 @@ protected RunContentDescriptor launch(@NotNull ExecutionEnvironment env) throws
171170
final String nameWithDeviceName = descriptor.getDisplayName() + " (" + device.deviceName() + ")";
172171

173172
try {
174-
// There is no public way to set display name so we resort to reflection.
175-
final Field f = descriptor.getClass().getDeclaredField("myDisplayNameView");
176-
f.setAccessible(true);
177-
Object viewInstance = f.get(descriptor);
178-
if (viewInstance != null) {
179-
final Method setValueMethod = viewInstance.getClass().getMethod("setValue", Object.class);
180-
setValueMethod.invoke(viewInstance, nameWithDeviceName);
181-
}
173+
// RunContentDescriptor.setDisplayName() is protected, so we use reflection to call it.
174+
final Method setDisplayName = RunContentDescriptor.class.getDeclaredMethod("setDisplayName", String.class);
175+
setDisplayName.setAccessible(true);
176+
setDisplayName.invoke(descriptor, nameWithDeviceName);
182177
}
183-
catch (IllegalAccessException | InvocationTargetException | NoSuchFieldException | NoSuchMethodException e) {
178+
catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
184179
FlutterUtils.info(LOG, "Error setting display name", e, true);
185180
}
186181

0 commit comments

Comments
 (0)