Skip to content

Commit 27965c3

Browse files
authored
[fix] target device selector updates (flutter#8891)
In flutter#8853, users are reporting an exception in Android Studio thanks to excessive toolbar updates. This is caused by the Flutter plugin triggering frequent global toolbar updates via a call to `ActivityTracker.getInstance().inc()` whenever the device or emulator lists change. **The Fix.** To reduce update frequency, this change makes the updates targeted, removing the (global)`ActivityTracker.getInstance().inc()` calls from `DeviceSelectorAction.updateActions()` and `DeviceService.refreshDeviceDaemon()`, invoking a newly extracted `updateComponent` method in `DeviceSelectorAction` instead. This ensures that the Flutter device selector UI still updates immediately when devices are connected or disconnected, but without forcing a global re-query of all actions on the toolbar. **Verification.** Verified manually and `io.flutter.actions.DeviceSelectorActionTest` still passes. Fixes flutter#8853 --- Review the contribution guidelines below: - [x] I’ve reviewed the contributor guide and applied the relevant portions to this PR. - [x] I've included the required information in the description above. - [x] My up-to-date information is in the `AUTHORS` file. - [x] I've updated `CHANGELOG.md` if appropriate. <details> <summary>Contribution guidelines:</summary><br> - See our [contributor guide](../CONTRIBUTING.md) and the [Flutter organization contributor guide]([https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md) 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](flutter#8098)). </details>
1 parent 2352bc0 commit 27965c3

2 files changed

Lines changed: 28 additions & 25 deletions

File tree

src/io/flutter/actions/DeviceSelectorAction.java

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
package io.flutter.actions;
77

88
import com.intellij.icons.AllIcons;
9-
import com.intellij.ide.ActivityTracker;
109
import com.intellij.ide.DataManager;
1110
import com.intellij.openapi.actionSystem.ActionUpdateThread;
1211
import com.intellij.openapi.actionSystem.AnAction;
@@ -46,6 +45,7 @@
4645
import io.flutter.run.FlutterDevice;
4746
import io.flutter.run.daemon.DeviceService;
4847
import io.flutter.sdk.AndroidEmulatorManager;
48+
import io.flutter.utils.AsyncUtils;
4949
import io.flutter.utils.FlutterModuleUtils;
5050
import org.jetbrains.annotations.NotNull;
5151
import org.jetbrains.annotations.Nullable;
@@ -381,14 +381,19 @@ public void projectClosing(@NotNull Project project) {
381381
update(project, presentation);
382382
}
383383

384+
updateComponent(project, presentation);
385+
}
386+
387+
private void updateComponent(@NotNull Project project, @NotNull Presentation presentation) {
384388
final DeviceService deviceService = DeviceService.getInstance(project);
385389
final FlutterDevice selectedDevice = deviceService.getSelectedDevice();
386390
final Collection<FlutterDevice> devices = deviceService.getConnectedDevices();
387391

388392
final String text;
389-
Icon icon = DEFAULT_DEVICE_ICON;
393+
Icon icon;
390394

391395
if (devices.isEmpty()) {
396+
icon = DEFAULT_DEVICE_ICON;
392397
final boolean isLoading = deviceService.getStatus() == DeviceService.State.LOADING;
393398
if (isLoading) {
394399
text = FlutterBundle.message("devicelist.loading");
@@ -398,6 +403,7 @@ public void projectClosing(@NotNull Project project) {
398403
}
399404
}
400405
else if (selectedDevice == null) {
406+
icon = DEFAULT_DEVICE_ICON;
401407
text = FlutterBundle.message("devicelist.noDeviceSelected");
402408
}
403409
else {
@@ -412,25 +418,27 @@ else if (selectedDevice == null) {
412418
// Update the custom component if it exists
413419
final JButton customComponent = presentation.getClientProperty(CUSTOM_COMPONENT_KEY);
414420
if (customComponent != null) {
415-
final @Nullable JBLabel iconLabel = (JBLabel)customComponent.getClientProperty(ICON_LABEL_KEY);
416-
final @Nullable JBLabel textLabel = (JBLabel)customComponent.getClientProperty(TEXT_LABEL_KEY);
421+
AsyncUtils.invokeLater(() -> {
422+
final @Nullable JBLabel iconLabel = (JBLabel)customComponent.getClientProperty(ICON_LABEL_KEY);
423+
final @Nullable JBLabel textLabel = (JBLabel)customComponent.getClientProperty(TEXT_LABEL_KEY);
417424

418-
if (iconLabel != null) {
419-
iconLabel.setIcon(icon);
420-
}
421-
if (textLabel != null) {
422-
textLabel.setText(text);
423-
// Update the foreground color to adapt to theme changes.
424-
textLabel.setForeground(getToolbarForegroundColor());
425-
customComponent.invalidate();
426-
Container parent = customComponent.getParent();
427-
while (parent != null) {
428-
parent.invalidate();
429-
parent = parent.getParent();
425+
if (iconLabel != null) {
426+
iconLabel.setIcon(icon);
430427
}
431-
customComponent.revalidate();
432-
customComponent.repaint();
433-
}
428+
if (textLabel != null) {
429+
textLabel.setText(text);
430+
// Update the foreground color to adapt to theme changes.
431+
textLabel.setForeground(getToolbarForegroundColor());
432+
customComponent.invalidate();
433+
Container parent = customComponent.getParent();
434+
while (parent != null) {
435+
parent.invalidate();
436+
parent = parent.getParent();
437+
}
438+
customComponent.revalidate();
439+
customComponent.repaint();
440+
}
441+
});
434442
}
435443
}
436444

@@ -447,6 +455,7 @@ private void update(@NotNull Project project, @NotNull Presentation presentation
447455
}
448456
updateActions(project, presentation);
449457
updateVisibility(project, presentation);
458+
updateComponent(project, presentation);
450459
}
451460

452461
private static void updateVisibility(final Project project, final @NotNull Presentation presentation) {
@@ -531,11 +540,6 @@ private void updateActions(@NotNull Project project, @NotNull Presentation prese
531540
// Atomically replace the action list
532541
LOG.debug("[" + projectName + "] Replacing device selector actions");
533542
this.actions = newActions;
534-
535-
var tracker = ActivityTracker.getInstance();
536-
if (tracker != null) {
537-
tracker.inc();
538-
}
539543
}
540544

541545
private static class SelectDeviceAction extends AnAction {

src/io/flutter/run/daemon/DeviceService.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,6 @@ private void refreshDeviceDaemon() {
191191
if (project.isDisposed()) return;
192192
deviceDaemon.refresh(this::chooseNextDaemon);
193193
refreshInProgress = false;
194-
ActivityTracker.getInstance().inc();
195194
});
196195
}
197196

0 commit comments

Comments
 (0)