FileDocCategorySizeDatePackage
DevicePanel.javaAPI DocAndroid 1.5 API28897Wed May 06 22:41:08 BST 2009com.android.ddmuilib

DevicePanel

public final class DevicePanel extends Panel implements com.android.ddmlib.AndroidDebugBridge.IClientChangeListener, com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener, com.android.ddmlib.AndroidDebugBridge.IDebugBridgeChangeListener
A display of both the devices and their clients.

Fields Summary
private static final String
PREFS_COL_NAME_SERIAL
private static final String
PREFS_COL_PID_STATE
private static final String
PREFS_COL_PORT_BUILD
private static final int
DEVICE_COL_SERIAL
private static final int
DEVICE_COL_STATE
private static final int
DEVICE_COL_BUILD
private static final int
CLIENT_COL_NAME
private static final int
CLIENT_COL_PID
private static final int
CLIENT_COL_THREAD
private static final int
CLIENT_COL_HEAP
private static final int
CLIENT_COL_PORT
public static final int
ICON_WIDTH
public static final String
ICON_THREAD
public static final String
ICON_HEAP
public static final String
ICON_HALT
public static final String
ICON_GC
private com.android.ddmlib.Device
mCurrentDevice
private com.android.ddmlib.Client
mCurrentClient
private org.eclipse.swt.widgets.Tree
mTree
private org.eclipse.jface.viewers.TreeViewer
mTreeViewer
private org.eclipse.swt.graphics.Image
mDeviceImage
private org.eclipse.swt.graphics.Image
mEmulatorImage
private org.eclipse.swt.graphics.Image
mThreadImage
private org.eclipse.swt.graphics.Image
mHeapImage
private org.eclipse.swt.graphics.Image
mWaitingImage
private org.eclipse.swt.graphics.Image
mDebuggerImage
private org.eclipse.swt.graphics.Image
mDebugErrorImage
private final ArrayList
mListeners
private final ArrayList
mDevicesToExpand
private IImageLoader
mLoader
private boolean
mAdvancedPortSupport
Constructors Summary
public DevicePanel(IImageLoader loader, boolean advancedPortSupport)
Creates the {@link DevicePanel} object.

param
loader
param
advancedPortSupport if true the device panel will add support for selected client port and display the ports in the ui.

        mLoader = loader;
        mAdvancedPortSupport = advancedPortSupport;
    
Methods Summary
public voidaddSelectionListener(com.android.ddmuilib.DevicePanel$IUiSelectionListener listener)

        mListeners.add(listener);
    
public voidbridgeChanged(com.android.ddmlib.AndroidDebugBridge bridge)
Sent when a new {@link AndroidDebugBridge} is started.

This is sent from a non UI thread.

param
bridge the new {@link AndroidDebugBridge} object.
see
IDebugBridgeChangeListener#serverChanged(AndroidDebugBridge)

        if (mTree.isDisposed() == false) {
            exec(new Runnable() {
                public void run() {
                    if (mTree.isDisposed() == false) {
                        // set up the data source.
                        mTreeViewer.setInput(bridge);

                        // notify the listener of a possible selection change.
                        notifyListeners();
                    } else {
                        // tree is disposed, we need to do something.
                        // lets remove ourselves from the listener.
                        AndroidDebugBridge.removeDebugBridgeChangeListener(DevicePanel.this);
                        AndroidDebugBridge.removeDeviceChangeListener(DevicePanel.this);
                        AndroidDebugBridge.removeClientChangeListener(DevicePanel.this);
                    }
                }
            });
        }

        // all current devices are obsolete
        synchronized (mDevicesToExpand) {
            mDevicesToExpand.clear();
        }
    
public voidclientChanged(com.android.ddmlib.Client client, int changeMask)
Sent when an existing client information changed.

This is sent from a non UI thread.

param
client the updated client.
param
changeMask the bit mask describing the changed properties. It can contain any of the following values: {@link Client#CHANGE_INFO}, {@link Client#CHANGE_DEBUGGER_INTEREST}, {@link Client#CHANGE_THREAD_MODE}, {@link Client#CHANGE_THREAD_DATA}, {@link Client#CHANGE_HEAP_MODE}, {@link Client#CHANGE_HEAP_DATA}, {@link Client#CHANGE_NATIVE_HEAP_DATA}
see
IClientChangeListener#clientChanged(Client, int)

        exec(new Runnable() {
            public void run() {
                if (mTree.isDisposed() == false) {
                    // refresh the client
                    mTreeViewer.refresh(client);

                    if ((changeMask & Client.CHANGE_DEBUGGER_INTEREST) ==
                            Client.CHANGE_DEBUGGER_INTEREST &&
                            client.getClientData().getDebuggerConnectionStatus() ==
                                ClientData.DEBUGGER_WAITING) {
                        // make sure the device is expanded. Normally the setSelection below
                        // will auto expand, but the children of device may not already exist
                        // at this time. Forcing an expand will make the TreeViewer create them.
                        Device device = client.getDevice();
                        if (mTreeViewer.getExpandedState(device) == false) {
                            mTreeViewer.setExpandedState(device, true);
                        }

                        // create and set the selection
                        TreePath treePath = new TreePath(new Object[] { device, client});
                        TreeSelection treeSelection = new TreeSelection(treePath);
                        mTreeViewer.setSelection(treeSelection);
                        
                        if (mAdvancedPortSupport) {
                            client.setAsSelectedClient();
                        }
                        
                        // notify the listener of a possible selection change.
                        notifyListeners(device, client);
                    }
                } else {
                    // tree is disposed, we need to do something.
                    // lets remove ourselves from the listener.
                    AndroidDebugBridge.removeDebugBridgeChangeListener(DevicePanel.this);
                    AndroidDebugBridge.removeDeviceChangeListener(DevicePanel.this);
                    AndroidDebugBridge.removeClientChangeListener(DevicePanel.this);
                }
            }
        });
    
protected org.eclipse.swt.widgets.ControlcreateControl(org.eclipse.swt.widgets.Composite parent)

        loadImages(parent.getDisplay(), mLoader);

        parent.setLayout(new FillLayout());

        // create the tree and its column
        mTree = new Tree(parent, SWT.SINGLE | SWT.FULL_SELECTION);
        mTree.setHeaderVisible(true);
        mTree.setLinesVisible(true);

        IPreferenceStore store = DdmUiPreferences.getStore();

        TableHelper.createTreeColumn(mTree, "Name", SWT.LEFT,
                "com.android.home", //$NON-NLS-1$
                PREFS_COL_NAME_SERIAL, store);
        TableHelper.createTreeColumn(mTree, "", SWT.LEFT, //$NON-NLS-1$
                "Offline", //$NON-NLS-1$
                PREFS_COL_PID_STATE, store);

        TreeColumn col = new TreeColumn(mTree, SWT.NONE);
        col.setWidth(ICON_WIDTH + 8);
        col.setResizable(false);
        col = new TreeColumn(mTree, SWT.NONE);
        col.setWidth(ICON_WIDTH + 8);
        col.setResizable(false);

        TableHelper.createTreeColumn(mTree, "", SWT.LEFT, //$NON-NLS-1$
                "9999-9999", //$NON-NLS-1$
                PREFS_COL_PORT_BUILD, store);

        // create the tree viewer
        mTreeViewer = new TreeViewer(mTree);

        // make the device auto expanded.
        mTreeViewer.setAutoExpandLevel(TreeViewer.ALL_LEVELS);

        // set up the content and label providers.
        mTreeViewer.setContentProvider(new ContentProvider());
        mTreeViewer.setLabelProvider(new LabelProvider());

        mTree.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                notifyListeners();
            }
        });

        return mTree;
    
public voiddeviceChanged(com.android.ddmlib.Device device, int changeMask)
Sent when a device data changed, or when clients are started/terminated on the device.

This is sent from a non UI thread.

param
device the device that was updated.
param
changeMask the mask indicating what changed.
see
IDeviceChangeListener#deviceChanged(Device)

        boolean expand = false;
        synchronized (mDevicesToExpand) {
            int index = mDevicesToExpand.indexOf(device);
            if (device.hasClients() && index != -1) {
                mDevicesToExpand.remove(index);
                expand = true;
            }
        }
        
        final boolean finalExpand = expand;

        exec(new Runnable() {
            public void run() {
                if (mTree.isDisposed() == false) {
                    // look if the current device is selected. This is done in case the current
                    // client of this particular device was killed. In this case, we'll need to
                    // manually reselect the device.
                    
                    Device selectedDevice = getSelectedDevice();

                    // refresh the device
                    mTreeViewer.refresh(device);
                    
                    // if the selected device was the changed device and the new selection is
                    // empty, we reselect the device.
                    if (selectedDevice == device && mTreeViewer.getSelection().isEmpty()) {
                        mTreeViewer.setSelection(new TreeSelection(new TreePath(
                                new Object[] { device })));
                    }
                    
                    // notify the listener of a possible selection change.
                    notifyListeners();
                    
                    if (finalExpand) {
                        mTreeViewer.setExpandedState(device, true);
                    }
                } else {
                    // tree is disposed, we need to do something.
                    // lets remove ourselves from the listener.
                    AndroidDebugBridge.removeDebugBridgeChangeListener(DevicePanel.this);
                    AndroidDebugBridge.removeDeviceChangeListener(DevicePanel.this);
                    AndroidDebugBridge.removeClientChangeListener(DevicePanel.this);
                }
            }
        });
    
public voiddeviceConnected(com.android.ddmlib.Device device)
Sent when the a device is connected to the {@link AndroidDebugBridge}.

This is sent from a non UI thread.

param
device the new device.
see
IDeviceChangeListener#deviceConnected(Device)

        exec(new Runnable() {
            public void run() {
                if (mTree.isDisposed() == false) {
                    // refresh all
                    mTreeViewer.refresh();

                    // notify the listener of a possible selection change.
                    notifyListeners();
                } else {
                    // tree is disposed, we need to do something.
                    // lets remove ourselves from the listener.
                    AndroidDebugBridge.removeDebugBridgeChangeListener(DevicePanel.this);
                    AndroidDebugBridge.removeDeviceChangeListener(DevicePanel.this);
                    AndroidDebugBridge.removeClientChangeListener(DevicePanel.this);
                }
            }
        });

        // if it doesn't have clients yet, it'll need to be manually expanded when it gets them.
        if (device.hasClients() == false) {
            synchronized (mDevicesToExpand) {
                mDevicesToExpand.add(device);
            }
        }
    
public voiddeviceDisconnected(com.android.ddmlib.Device device)
Sent when the a device is connected to the {@link AndroidDebugBridge}.

This is sent from a non UI thread.

param
device the new device.
see
IDeviceChangeListener#deviceDisconnected(Device)

        deviceConnected(device);
        
        // just in case, we remove it from the list of devices to expand.
        synchronized (mDevicesToExpand) {
            mDevicesToExpand.remove(device);
        }
    
public voiddispose()

        AndroidDebugBridge.removeDebugBridgeChangeListener(this);
        AndroidDebugBridge.removeDeviceChangeListener(this);
        AndroidDebugBridge.removeClientChangeListener(this);
    
private voidexec(java.lang.Runnable runnable)
Executes the {@link Runnable} in the UI thread.

param
runnable the runnable to execute.

        try {
            Display display = mTree.getDisplay();
            display.asyncExec(runnable);
        } catch (SWTException e) {
            // tree is disposed, we need to do something. lets remove ourselves from the listener.
            AndroidDebugBridge.removeDebugBridgeChangeListener(this);
            AndroidDebugBridge.removeDeviceChangeListener(this);
            AndroidDebugBridge.removeClientChangeListener(this);
        }
    
public voidforceGcOnSelectedClient()
Forces a GC on the selected {@link Client}.

        if (mCurrentClient != null) {
            mCurrentClient.executeGarbageCollector();
        }
    
public com.android.ddmlib.ClientgetSelectedClient()
Returns the selected {@link Client}. May be null.

        return mCurrentClient;
    
public com.android.ddmlib.DevicegetSelectedDevice()
Returns the selected {@link Device}. If a {@link Client} is selected, it returns the Device object containing the client.

        return mCurrentDevice;
    
private static java.lang.StringgetStateString(com.android.ddmlib.Device d)
Returns a display string representing the state of the device.

param
d the device

        DeviceState deviceState = d.getState();
        if (deviceState == DeviceState.ONLINE) {
            return "Online";
        } else if (deviceState == DeviceState.OFFLINE) {
            return "Offline";
        } else if (deviceState == DeviceState.BOOTLOADER) {
            return "Bootloader";
        }

        return "??";
    
public voidkillSelectedClient()
Kills the selected {@link Client} by sending its VM a halt command.

        if (mCurrentClient != null) {
            Client client = mCurrentClient;
            
            // reset the selection to the device.
            TreePath treePath = new TreePath(new Object[] { mCurrentDevice });
            TreeSelection treeSelection = new TreeSelection(treePath);
            mTreeViewer.setSelection(treeSelection);

            client.kill();
        }
    
private voidloadImages(org.eclipse.swt.widgets.Display display, IImageLoader loader)

        if (mDeviceImage == null) {
            mDeviceImage = ImageHelper.loadImage(loader, display, "device.png", //$NON-NLS-1$
                    ICON_WIDTH, ICON_WIDTH,
                    display.getSystemColor(SWT.COLOR_RED));
        }
        if (mEmulatorImage == null) {
            mEmulatorImage = ImageHelper.loadImage(loader, display,
                    "emulator.png", ICON_WIDTH, ICON_WIDTH, //$NON-NLS-1$
                    display.getSystemColor(SWT.COLOR_BLUE));
        }
        if (mThreadImage == null) {
            mThreadImage = ImageHelper.loadImage(loader, display, ICON_THREAD,
                    ICON_WIDTH, ICON_WIDTH,
                    display.getSystemColor(SWT.COLOR_YELLOW));
        }
        if (mHeapImage == null) {
            mHeapImage = ImageHelper.loadImage(loader, display, ICON_HEAP,
                    ICON_WIDTH, ICON_WIDTH,
                    display.getSystemColor(SWT.COLOR_BLUE));
        }
        if (mWaitingImage == null) {
            mWaitingImage = ImageHelper.loadImage(loader, display,
                    "debug-wait.png", ICON_WIDTH, ICON_WIDTH, //$NON-NLS-1$
                    display.getSystemColor(SWT.COLOR_RED));
        }
        if (mDebuggerImage == null) {
            mDebuggerImage = ImageHelper.loadImage(loader, display,
                    "debug-attach.png", ICON_WIDTH, ICON_WIDTH, //$NON-NLS-1$
                    display.getSystemColor(SWT.COLOR_GREEN));
        }
        if (mDebugErrorImage == null) {
            mDebugErrorImage = ImageHelper.loadImage(loader, display,
                    "debug-error.png", ICON_WIDTH, ICON_WIDTH, //$NON-NLS-1$
                    display.getSystemColor(SWT.COLOR_RED));
        }
    
private voidnotifyListeners()

        // get the selection
        TreeItem[] items = mTree.getSelection();

        Client client = null;
        Device device = null;

        if (items.length == 1) {
            Object object = items[0].getData();
            if (object instanceof Client) {
                client = (Client)object;
                device = client.getDevice();
            } else if (object instanceof Device) {
                device = (Device)object;
            }
        }

        notifyListeners(device, client);
    
private voidnotifyListeners(com.android.ddmlib.Device selectedDevice, com.android.ddmlib.Client selectedClient)

        if (selectedDevice != mCurrentDevice || selectedClient != mCurrentClient) {
            mCurrentDevice = selectedDevice;
            mCurrentClient = selectedClient;
        
            for (IUiSelectionListener listener : mListeners) {
                // notify the listener with a try/catch-all to make sure this thread won't die
                // because of an uncaught exception before all the listeners were notified.
                try {
                    listener.selectionChanged(selectedDevice, selectedClient);
                } catch (Exception e) {
                }
            }
        }
    
protected voidpostCreation()

        // ask for notification of changes in AndroidDebugBridge (a new one is created when
        // adb is restarted from a different location), Device and Client objects.
        AndroidDebugBridge.addDebugBridgeChangeListener(this);
        AndroidDebugBridge.addDeviceChangeListener(this);
        AndroidDebugBridge.addClientChangeListener(this);
    
public voidremoveSelectionListener(com.android.ddmuilib.DevicePanel$IUiSelectionListener listener)

        mListeners.remove(listener);
    
public voidsetEnabledHeapOnSelectedClient(boolean enable)

        if (mCurrentClient != null) {
            mCurrentClient.setHeapUpdateEnabled(enable);
        }
    
public voidsetEnabledThreadOnSelectedClient(boolean enable)

        if (mCurrentClient != null) {
            mCurrentClient.setThreadUpdateEnabled(enable);
        }
    
public voidsetFocus()
Sets the focus to the proper control inside the panel.

        mTree.setFocus();