blob: 0c9d8c25c184ed61c46080cefae021724523d559 [file] [log] [blame]
/*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.tools.idea.ddms;
import com.android.ddmlib.AndroidDebugBridge;
import com.android.ddmlib.Client;
import com.android.ddmlib.IDevice;
import com.android.tools.idea.model.AndroidModuleInfo;
import com.google.common.collect.Maps;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Disposer;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.Map;
public class DevicePanel implements AndroidDebugBridge.IDeviceChangeListener, AndroidDebugBridge.IDebugBridgeChangeListener,
AndroidDebugBridge.IClientChangeListener, Disposable {
private JPanel myPanel;
private final DeviceContext myDeviceContext;
@Nullable private AndroidDebugBridge myBridge;
@NotNull private final Project myProject;
@NotNull private final Map<String, String> myPreferredClients;
public boolean myIgnoreActionEvents;
@NotNull private JComboBox myDeviceCombo;
@NotNull private JComboBox myClientCombo;
@Nullable private String myCandidateClientName;
public DevicePanel(@NotNull Project project, @NotNull DeviceContext context) {
myProject = project;
myDeviceContext = context;
myPreferredClients = Maps.newHashMap();
myCandidateClientName = getApplicationName();
Disposer.register(myProject, this);
initializeDeviceCombo();
initializeClientCombo();
AndroidDebugBridge.addDeviceChangeListener(this);
AndroidDebugBridge.addClientChangeListener(this);
AndroidDebugBridge.addDebugBridgeChangeListener(this);
}
private void initializeDeviceCombo() {
myDeviceCombo.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
if (myIgnoreActionEvents) return;
updateClientCombo();
Object sel = myDeviceCombo.getSelectedItem();
IDevice device = (sel instanceof IDevice) ? (IDevice)sel : null;
myDeviceContext.fireDeviceSelected(device);
}
});
myDeviceCombo.setRenderer(new DeviceRenderer.DeviceComboBoxRenderer("No Connected Devices"));
Dimension size = myDeviceCombo.getMinimumSize();
myDeviceCombo.setMinimumSize(new Dimension(200, size.height));
}
private void initializeClientCombo() {
myClientCombo.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent actionEvent) {
if (myIgnoreActionEvents) return;
Client client = (Client)myClientCombo.getSelectedItem();
if (client != null) {
myPreferredClients.put(client.getDevice().getName(), client.getClientData().getClientDescription());
}
myDeviceContext.fireClientSelected(client);
}
});
myClientCombo.setRenderer(new ClientCellRenderer("No Debuggable Applications"));
Dimension size = myClientCombo.getMinimumSize();
myClientCombo.setMinimumSize(new Dimension(250, size.height));
}
public void selectDevice(IDevice device) {
myDeviceCombo.setSelectedItem(device);
}
public void selectClient(Client client) {
myClientCombo.setSelectedItem(client);
}
@Nullable
private String getApplicationName() {
for (Module module : ModuleManager.getInstance(myProject).getModules()) {
AndroidModuleInfo moduleInfo = AndroidModuleInfo.get(module);
if (moduleInfo != null) {
String pkg = moduleInfo.getPackage();
if (pkg != null) {
return pkg;
}
}
}
return null;
}
@Override
public void dispose() {
if (myBridge != null) {
AndroidDebugBridge.removeDeviceChangeListener(this);
AndroidDebugBridge.removeClientChangeListener(this);
AndroidDebugBridge.removeDebugBridgeChangeListener(this);
myBridge = null;
}
}
public JPanel getComponent() {
return myPanel;
}
@Override
public void bridgeChanged(final AndroidDebugBridge bridge) {
UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
myBridge = bridge;
updateDeviceCombo();
}
});
}
@Override
public void deviceConnected(final IDevice device) {
UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
updateDeviceCombo();
}
});
}
@Override
public void deviceDisconnected(final IDevice device) {
UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
updateDeviceCombo();
}
});
}
@Override
public void deviceChanged(final IDevice device, final int changeMask) {
UIUtil.invokeLaterIfNeeded(new Runnable() {
@Override
public void run() {
if ((changeMask & IDevice.CHANGE_CLIENT_LIST) != 0) {
updateClientCombo();
}
else if ((changeMask & IDevice.CHANGE_STATE) != 0) {
updateDeviceCombo();
}
if (device != null) {
myDeviceContext.fireDeviceChanged(device, changeMask);
}
}
});
}
@Override
public void clientChanged(Client client, int changeMask) {
if ((changeMask & Client.CHANGE_NAME) != 0) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
updateClientCombo();
}
});
}
}
private void updateDeviceCombo() {
myIgnoreActionEvents = true;
boolean update = true;
IDevice selected = (IDevice)myDeviceCombo.getSelectedItem();
myDeviceCombo.removeAllItems();
if (myBridge != null) {
for (IDevice device : myBridge.getDevices()) {
myDeviceCombo.addItem(device);
if (selected == device) {
myDeviceCombo.setSelectedItem(device);
update = false;
}
}
}
if (update) {
myDeviceContext.fireDeviceSelected((IDevice)myDeviceCombo.getSelectedItem());
updateClientCombo();
}
myIgnoreActionEvents = false;
}
private void updateClientCombo() {
myIgnoreActionEvents = true;
IDevice device = (IDevice)myDeviceCombo.getSelectedItem();
Client selected = (Client)myClientCombo.getSelectedItem();
Client toSelect = selected;
boolean update = true;
myClientCombo.removeAllItems();
if (device != null) {
// Change the currently selected client if the user has a preference.
String preferred = getPreferredClientForDevice(device.getName());
if (preferred != null) {
Client preferredClient = device.getClient(preferred);
if (preferredClient != null) {
toSelect = preferredClient;
}
}
Client[] clients = device.getClients();
// There's a chance we got this update because a client we were debugging
// just crashed or was closed. We still want to keep it in the list
// though so the user can look over any final error messages / profiling
// states.
boolean selectedClientDied = true;
Arrays.sort(clients, new ClientCellRenderer.ClientComparator());
for (Client client : clients) {
myClientCombo.addItem(client);
if (selected == client) {
selectedClientDied = false;
}
}
if (selectedClientDied) {
myClientCombo.addItem(selected);
}
myClientCombo.setSelectedItem(toSelect);
update = toSelect != selected;
}
myIgnoreActionEvents = false;
if (update) {
myDeviceContext.fireClientSelected((Client)myClientCombo.getSelectedItem());
}
}
@Nullable
private String getPreferredClientForDevice(String deviceName) {
String client = myPreferredClients.get(deviceName);
return client == null ? myCandidateClientName : client;
}
}