aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/DeviceChooserDialog.java
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/DeviceChooserDialog.java')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/DeviceChooserDialog.java824
1 files changed, 824 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/DeviceChooserDialog.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/DeviceChooserDialog.java
new file mode 100644
index 000000000..995ccdf46
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/DeviceChooserDialog.java
@@ -0,0 +1,824 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
+ *
+ * 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.ide.eclipse.adt.internal.launch;
+
+import com.android.ddmlib.AndroidDebugBridge;
+import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener;
+import com.android.ddmlib.Client;
+import com.android.ddmlib.IDevice;
+import com.android.ddmlib.IDevice.DeviceState;
+import com.android.ddmuilib.ImageLoader;
+import com.android.ddmuilib.TableHelper;
+import com.android.ide.eclipse.adt.internal.editors.IconFactory;
+import com.android.ide.eclipse.adt.internal.sdk.AdtConsoleSdkLog;
+import com.android.ide.eclipse.adt.internal.sdk.Sdk;
+import com.android.ide.eclipse.ddms.DdmsPlugin;
+import com.android.sdklib.AndroidVersion;
+import com.android.sdklib.IAndroidTarget;
+import com.android.sdklib.internal.avd.AvdInfo;
+import com.android.sdkuilib.internal.widgets.AvdSelector;
+import com.android.sdkuilib.internal.widgets.AvdSelector.DisplayMode;
+import com.android.sdkuilib.internal.widgets.AvdSelector.IAvdFilter;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.viewers.ILabelProviderListener;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.SWTException;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.swt.widgets.Table;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A dialog that lets the user choose a device to deploy an application.
+ * The user can either choose an exiting running device (including running emulators)
+ * or start a new emulator using an Android Virtual Device configuration that matches
+ * the current project.
+ */
+public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener {
+
+ private final static int ICON_WIDTH = 16;
+
+ private Table mDeviceTable;
+ private TableViewer mViewer;
+ private AvdSelector mPreferredAvdSelector;
+
+ private Image mDeviceImage;
+ private Image mEmulatorImage;
+ private Image mMatchImage;
+ private Image mNoMatchImage;
+ private Image mWarningImage;
+
+ private final DeviceChooserResponse mResponse;
+ private final String mPackageName;
+ private final IAndroidTarget mProjectTarget;
+ private final AndroidVersion mMinApiVersion;
+ private final Sdk mSdk;
+
+ private Button mDeviceRadioButton;
+ private Button mUseDeviceForFutureLaunchesCheckbox;
+ private boolean mUseDeviceForFutureLaunches;
+
+ private boolean mDisableAvdSelectionChange = false;
+
+ /**
+ * Basic Content Provider for a table full of {@link IDevice} objects. The input is
+ * a {@link AndroidDebugBridge}.
+ */
+ private class ContentProvider implements IStructuredContentProvider {
+ @Override
+ public Object[] getElements(Object inputElement) {
+ if (inputElement instanceof AndroidDebugBridge) {
+ return findCompatibleDevices(((AndroidDebugBridge)inputElement).getDevices());
+ }
+
+ return new Object[0];
+ }
+
+ private Object[] findCompatibleDevices(IDevice[] devices) {
+ if (devices == null) {
+ return null;
+ }
+
+ List<IDevice> compatibleDevices = new ArrayList<IDevice>(devices.length);
+ for (IDevice device : devices) {
+ AndroidVersion deviceVersion = Sdk.getDeviceVersion(device);
+ if (deviceVersion == null || deviceVersion.canRun(mMinApiVersion)) {
+ compatibleDevices.add(device);
+ }
+ }
+
+ return compatibleDevices.toArray();
+ }
+
+ @Override
+ public void dispose() {
+ // pass
+ }
+
+ @Override
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ // pass
+ }
+ }
+
+ /**
+ * A Label Provider for the {@link TableViewer} in {@link DeviceChooserDialog}.
+ * It provides labels and images for {@link IDevice} objects.
+ */
+ private class LabelProvider implements ITableLabelProvider {
+
+ @Override
+ public Image getColumnImage(Object element, int columnIndex) {
+ if (element instanceof IDevice) {
+ IDevice device = (IDevice)element;
+ switch (columnIndex) {
+ case 0:
+ return device.isEmulator() ? mEmulatorImage : mDeviceImage;
+
+ case 2:
+ // check for compatibility.
+ if (device.isEmulator() == false) { // physical device
+ // get the version of the device
+ AndroidVersion deviceVersion = Sdk.getDeviceVersion(device);
+ if (deviceVersion == null) {
+ return mWarningImage;
+ } else {
+ if (!deviceVersion.canRun(mMinApiVersion)) {
+ return mNoMatchImage;
+ }
+
+ // if the project is compiling against an add-on,
+ // the optional API may be missing from the device.
+ return mProjectTarget.isPlatform() ?
+ mMatchImage : mWarningImage;
+ }
+ } else {
+ // get the AvdInfo
+ AvdInfo info = mSdk.getAvdManager().getAvd(device.getAvdName(),
+ true /*validAvdOnly*/);
+ AvdCompatibility.Compatibility c =
+ AvdCompatibility.canRun(info, mProjectTarget,
+ mMinApiVersion);
+ switch (c) {
+ case YES:
+ return mMatchImage;
+ case NO:
+ return mNoMatchImage;
+ case UNKNOWN:
+ return mWarningImage;
+ }
+ }
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public String getColumnText(Object element, int columnIndex) {
+ if (element instanceof IDevice) {
+ IDevice device = (IDevice)element;
+ switch (columnIndex) {
+ case 0:
+ return device.getName();
+ case 1:
+ if (device.isEmulator()) {
+ return device.getAvdName();
+ } else {
+ return "N/A"; // devices don't have AVD names.
+ }
+ case 2:
+ if (device.isEmulator()) {
+ AvdInfo info = mSdk.getAvdManager().getAvd(device.getAvdName(),
+ true /*validAvdOnly*/);
+ if (info == null) {
+ return "?";
+ }
+ return info.getTarget().getFullName();
+ } else {
+ String deviceBuild = device.getProperty(IDevice.PROP_BUILD_VERSION);
+ if (deviceBuild == null) {
+ return "unknown";
+ }
+ return deviceBuild;
+ }
+ case 3:
+ String debuggable = device.getProperty(IDevice.PROP_DEBUGGABLE);
+ if (debuggable != null && debuggable.equals("1")) { //$NON-NLS-1$
+ return "Yes";
+ } else {
+ return "";
+ }
+ case 4:
+ return getStateString(device);
+ }
+ }
+
+ return null;
+ }
+
+ @Override
+ public void addListener(ILabelProviderListener listener) {
+ // pass
+ }
+
+ @Override
+ public void dispose() {
+ // pass
+ }
+
+ @Override
+ public boolean isLabelProperty(Object element, String property) {
+ // pass
+ return false;
+ }
+
+ @Override
+ public void removeListener(ILabelProviderListener listener) {
+ // pass
+ }
+ }
+
+ public static class DeviceChooserResponse {
+ private AvdInfo mAvdToLaunch;
+ private IDevice mDeviceToUse;
+ private boolean mUseDeviceForFutureLaunches;
+
+ public void setDeviceToUse(IDevice d) {
+ mDeviceToUse = d;
+ mAvdToLaunch = null;
+ }
+
+ public void setAvdToLaunch(AvdInfo avd) {
+ mAvdToLaunch = avd;
+ mDeviceToUse = null;
+ }
+
+ public IDevice getDeviceToUse() {
+ return mDeviceToUse;
+ }
+
+ public AvdInfo getAvdToLaunch() {
+ return mAvdToLaunch;
+ }
+
+ public void setUseDeviceForFutureLaunches(boolean en) {
+ mUseDeviceForFutureLaunches = en;
+ }
+
+ public boolean useDeviceForFutureLaunches() {
+ return mUseDeviceForFutureLaunches;
+ }
+ }
+
+ public DeviceChooserDialog(Shell parent, DeviceChooserResponse response, String packageName,
+ IAndroidTarget projectTarget, AndroidVersion minApiVersion,
+ boolean useDeviceForFutureLaunches) {
+ super(parent);
+
+ mResponse = response;
+ mPackageName = packageName;
+ mProjectTarget = projectTarget;
+ mMinApiVersion = minApiVersion;
+ mSdk = Sdk.getCurrent();
+ mUseDeviceForFutureLaunches = useDeviceForFutureLaunches;
+
+ AndroidDebugBridge.addDeviceChangeListener(this);
+ loadImages();
+ }
+
+ private void cleanup() {
+ // done listening.
+ AndroidDebugBridge.removeDeviceChangeListener(this);
+ }
+
+ @Override
+ protected void okPressed() {
+ cleanup();
+ super.okPressed();
+ }
+
+ @Override
+ protected void cancelPressed() {
+ cleanup();
+ super.cancelPressed();
+ }
+
+ @Override
+ protected Control createContents(Composite parent) {
+ Control content = super.createContents(parent);
+
+ // this must be called after createContents() has happened so that the
+ // ok button has been created (it's created after the call to createDialogArea)
+ updateDefaultSelection();
+
+ return content;
+ }
+
+ /**
+ * Create the button bar: We override the Dialog implementation of this method
+ * so that we can create the checkbox at the same level as the 'Cancel' and 'OK' buttons.
+ */
+ @Override
+ protected Control createButtonBar(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NONE);
+
+ GridLayout layout = new GridLayout(1, false);
+ layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
+ composite.setLayout(layout);
+ composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ mUseDeviceForFutureLaunchesCheckbox = new Button(composite, SWT.CHECK);
+ mUseDeviceForFutureLaunchesCheckbox.setSelection(mUseDeviceForFutureLaunches);
+ mResponse.setUseDeviceForFutureLaunches(mUseDeviceForFutureLaunches);
+ mUseDeviceForFutureLaunchesCheckbox.setText("Use same device for future launches");
+ mUseDeviceForFutureLaunchesCheckbox.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ mUseDeviceForFutureLaunches =
+ mUseDeviceForFutureLaunchesCheckbox.getSelection();
+ mResponse.setUseDeviceForFutureLaunches(mUseDeviceForFutureLaunches);
+ }
+ });
+ mUseDeviceForFutureLaunchesCheckbox.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ createButton(composite, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
+ createButton(composite, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
+
+ return composite;
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ // set dialog title
+ getShell().setText("Android Device Chooser");
+
+ Composite top = new Composite(parent, SWT.NONE);
+ top.setLayout(new GridLayout(1, true));
+
+ String msg;
+ if (mProjectTarget.isPlatform()) {
+ msg = String.format("Select a device with min API level %s.",
+ mMinApiVersion.getApiString());
+ } else {
+ msg = String.format("Select a device compatible with target %s.",
+ mProjectTarget.getFullName());
+ }
+ Label label = new Label(top, SWT.NONE);
+ label.setText(msg);
+
+ mDeviceRadioButton = new Button(top, SWT.RADIO);
+ mDeviceRadioButton.setText("Choose a running Android device");
+ mDeviceRadioButton.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ boolean deviceMode = mDeviceRadioButton.getSelection();
+
+ mDeviceTable.setEnabled(deviceMode);
+ mPreferredAvdSelector.setEnabled(!deviceMode);
+
+ if (deviceMode) {
+ handleDeviceSelection();
+ } else {
+ mResponse.setAvdToLaunch(mPreferredAvdSelector.getSelected());
+ }
+
+ enableOkButton();
+ }
+ });
+ mDeviceRadioButton.setSelection(true);
+
+
+ // offset the selector from the radio button
+ Composite offsetComp = new Composite(top, SWT.NONE);
+ offsetComp.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ GridLayout layout = new GridLayout(1, false);
+ layout.marginRight = layout.marginHeight = 0;
+ layout.marginLeft = 30;
+ offsetComp.setLayout(layout);
+
+ mDeviceTable = new Table(offsetComp, SWT.SINGLE | SWT.FULL_SELECTION | SWT.BORDER);
+ GridData gd;
+ mDeviceTable.setLayoutData(gd = new GridData(GridData.FILL_BOTH));
+ gd.heightHint = 100;
+
+ mDeviceTable.setHeaderVisible(true);
+ mDeviceTable.setLinesVisible(true);
+
+ TableHelper.createTableColumn(mDeviceTable, "Serial Number",
+ SWT.LEFT, "AAA+AAAAAAAAAAAAAAAAAAA", //$NON-NLS-1$
+ null /* prefs name */, null /* prefs store */);
+
+ TableHelper.createTableColumn(mDeviceTable, "AVD Name",
+ SWT.LEFT, "AAAAAAAAAAAAAAAAAAA", //$NON-NLS-1$
+ null /* prefs name */, null /* prefs store */);
+
+ TableHelper.createTableColumn(mDeviceTable, "Target",
+ SWT.LEFT, "AAA+Android 9.9.9", //$NON-NLS-1$
+ null /* prefs name */, null /* prefs store */);
+
+ TableHelper.createTableColumn(mDeviceTable, "Debug",
+ SWT.LEFT, "Debug", //$NON-NLS-1$
+ null /* prefs name */, null /* prefs store */);
+
+ TableHelper.createTableColumn(mDeviceTable, "State",
+ SWT.LEFT, "bootloader", //$NON-NLS-1$
+ null /* prefs name */, null /* prefs store */);
+
+ // create the viewer for it
+ mViewer = new TableViewer(mDeviceTable);
+ mViewer.setContentProvider(new ContentProvider());
+ mViewer.setLabelProvider(new LabelProvider());
+ mViewer.setInput(AndroidDebugBridge.getBridge());
+
+ mDeviceTable.addSelectionListener(new SelectionAdapter() {
+ /**
+ * Handles single-click selection on the device selector.
+ * {@inheritDoc}
+ */
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ handleDeviceSelection();
+ }
+
+ /**
+ * Handles double-click selection on the device selector.
+ * Note that the single-click handler will probably already have been called.
+ * {@inheritDoc}
+ */
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ handleDeviceSelection();
+ if (isOkButtonEnabled()) {
+ okPressed();
+ }
+ }
+ });
+
+ Button radio2 = new Button(top, SWT.RADIO);
+ radio2.setText("Launch a new Android Virtual Device");
+
+ // offset the selector from the radio button
+ offsetComp = new Composite(top, SWT.NONE);
+ offsetComp.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ layout = new GridLayout(1, false);
+ layout.marginRight = layout.marginHeight = 0;
+ layout.marginLeft = 30;
+ offsetComp.setLayout(layout);
+
+ mPreferredAvdSelector = new AvdSelector(offsetComp,
+ mSdk.getSdkOsLocation(),
+ mSdk.getAvdManager(),
+ new NonRunningAvdFilter(),
+ DisplayMode.SIMPLE_SELECTION,
+ new AdtConsoleSdkLog());
+ mPreferredAvdSelector.setTableHeightHint(100);
+ mPreferredAvdSelector.setEnabled(false);
+ mPreferredAvdSelector.setSelectionListener(new SelectionAdapter() {
+ /**
+ * Handles single-click selection on the AVD selector.
+ * {@inheritDoc}
+ */
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ if (mDisableAvdSelectionChange == false) {
+ mResponse.setAvdToLaunch(mPreferredAvdSelector.getSelected());
+ enableOkButton();
+ }
+ }
+
+ /**
+ * Handles double-click selection on the AVD selector.
+ *
+ * Note that the single-click handler will probably already have been called
+ * but the selected item can have changed in between.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ widgetSelected(e);
+ if (isOkButtonEnabled()) {
+ okPressed();
+ }
+ }
+ });
+
+ return top;
+ }
+
+ private void loadImages() {
+ ImageLoader ddmUiLibLoader = ImageLoader.getDdmUiLibLoader();
+ Display display = DdmsPlugin.getDisplay();
+ IconFactory factory = IconFactory.getInstance();
+
+ if (mDeviceImage == null) {
+ mDeviceImage = ddmUiLibLoader.loadImage(display,
+ "device.png", //$NON-NLS-1$
+ ICON_WIDTH, ICON_WIDTH,
+ display.getSystemColor(SWT.COLOR_RED));
+ }
+ if (mEmulatorImage == null) {
+ mEmulatorImage = ddmUiLibLoader.loadImage(display,
+ "emulator.png", ICON_WIDTH, ICON_WIDTH, //$NON-NLS-1$
+ display.getSystemColor(SWT.COLOR_BLUE));
+ }
+
+ if (mMatchImage == null) {
+ mMatchImage = factory.getIcon("match", //$NON-NLS-1$
+ IconFactory.COLOR_GREEN,
+ IconFactory.SHAPE_DEFAULT);
+ }
+
+ if (mNoMatchImage == null) {
+ mNoMatchImage = factory.getIcon("error", //$NON-NLS-1$
+ IconFactory.COLOR_RED,
+ IconFactory.SHAPE_DEFAULT);
+ }
+
+ if (mWarningImage == null) {
+ mWarningImage = factory.getIcon("warning", //$NON-NLS-1$
+ SWT.COLOR_YELLOW,
+ IconFactory.SHAPE_DEFAULT);
+ }
+
+ }
+
+ /**
+ * Returns a display string representing the state of the device.
+ * @param d the device
+ */
+ private static String getStateString(IDevice d) {
+ 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 "??";
+ }
+
+ /**
+ * Sent when the a device is connected to the {@link AndroidDebugBridge}.
+ * <p/>
+ * This is sent from a non UI thread.
+ * @param device the new device.
+ *
+ * @see IDeviceChangeListener#deviceConnected(IDevice)
+ */
+ @Override
+ public void deviceConnected(IDevice device) {
+ final DeviceChooserDialog dialog = this;
+ exec(new Runnable() {
+ @Override
+ public void run() {
+ if (mDeviceTable.isDisposed() == false) {
+ // refresh all
+ mViewer.refresh();
+
+ // update the selection
+ updateDefaultSelection();
+
+ // update the display of AvdInfo (since it's filtered to only display
+ // non running AVD.)
+ refillAvdList(false /*reloadAvds*/);
+ } else {
+ // table is disposed, we need to do something.
+ // lets remove ourselves from the listener.
+ AndroidDebugBridge.removeDeviceChangeListener(dialog);
+ }
+
+ }
+ });
+ }
+
+ /**
+ * Sent when the a device is connected to the {@link AndroidDebugBridge}.
+ * <p/>
+ * This is sent from a non UI thread.
+ * @param device the new device.
+ *
+ * @see IDeviceChangeListener#deviceDisconnected(IDevice)
+ */
+ @Override
+ public void deviceDisconnected(IDevice device) {
+ deviceConnected(device);
+ }
+
+ /**
+ * Sent when a device data changed, or when clients are started/terminated on the device.
+ * <p/>
+ * 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(IDevice, int)
+ */
+ @Override
+ public void deviceChanged(final IDevice device, int changeMask) {
+ if ((changeMask & (IDevice.CHANGE_STATE | IDevice.CHANGE_BUILD_INFO)) != 0) {
+ final DeviceChooserDialog dialog = this;
+ exec(new Runnable() {
+ @Override
+ public void run() {
+ if (mDeviceTable.isDisposed() == false) {
+ // refresh the device
+ mViewer.refresh(device);
+
+ // update the defaultSelection.
+ updateDefaultSelection();
+
+ // update the display of AvdInfo (since it's filtered to only display
+ // non running AVD). This is done on deviceChanged because the avd name
+ // of a (emulator) device may be updated as the emulator boots.
+
+ refillAvdList(false /*reloadAvds*/);
+
+ // if the changed device is the current selection,
+ // we update the OK button based on its state.
+ if (device == mResponse.getDeviceToUse()) {
+ enableOkButton();
+ }
+
+ } else {
+ // table is disposed, we need to do something.
+ // lets remove ourselves from the listener.
+ AndroidDebugBridge.removeDeviceChangeListener(dialog);
+ }
+ }
+ });
+ }
+ }
+
+ /**
+ * Returns whether the dialog is in "device" mode (true), or in "avd" mode (false).
+ */
+ private boolean isDeviceMode() {
+ return mDeviceRadioButton.getSelection();
+ }
+
+ /**
+ * Enables or disables the OK button of the dialog based on various selections in the dialog.
+ */
+ private void enableOkButton() {
+ Button okButton = getButton(IDialogConstants.OK_ID);
+
+ if (isDeviceMode()) {
+ okButton.setEnabled(mResponse.getDeviceToUse() != null &&
+ mResponse.getDeviceToUse().isOnline());
+ } else {
+ okButton.setEnabled(mResponse.getAvdToLaunch() != null);
+ }
+ }
+
+ /**
+ * Returns true if the ok button is enabled.
+ */
+ private boolean isOkButtonEnabled() {
+ Button okButton = getButton(IDialogConstants.OK_ID);
+ return okButton.isEnabled();
+ }
+
+ /**
+ * Executes the {@link Runnable} in the UI thread.
+ * @param runnable the runnable to execute.
+ */
+ private void exec(Runnable runnable) {
+ try {
+ Display display = mDeviceTable.getDisplay();
+ display.asyncExec(runnable);
+ } catch (SWTException e) {
+ // tree is disposed, we need to do something. lets remove ourselves from the listener.
+ AndroidDebugBridge.removeDeviceChangeListener(this);
+ }
+ }
+
+ private void handleDeviceSelection() {
+ int count = mDeviceTable.getSelectionCount();
+ if (count != 1) {
+ handleSelection(null);
+ } else {
+ int index = mDeviceTable.getSelectionIndex();
+ Object data = mViewer.getElementAt(index);
+ if (data instanceof IDevice) {
+ handleSelection((IDevice)data);
+ } else {
+ handleSelection(null);
+ }
+ }
+ }
+
+ private void handleSelection(IDevice device) {
+ mResponse.setDeviceToUse(device);
+ enableOkButton();
+ }
+
+ /**
+ * Look for a default device to select. This is done by looking for the running
+ * clients on each device and finding one similar to the one being launched.
+ * <p/>
+ * This is done every time the device list changed unless there is a already selection.
+ */
+ private void updateDefaultSelection() {
+ if (mDeviceTable.getSelectionCount() == 0) {
+ AndroidDebugBridge bridge = AndroidDebugBridge.getBridge();
+
+ IDevice[] devices = bridge.getDevices();
+
+ for (IDevice device : devices) {
+ Client[] clients = device.getClients();
+
+ for (Client client : clients) {
+
+ if (mPackageName.equals(client.getClientData().getClientDescription())) {
+ // found a match! Select it.
+ mViewer.setSelection(new StructuredSelection(device));
+ handleSelection(device);
+
+ // and we're done.
+ return;
+ }
+ }
+ }
+ }
+
+ handleDeviceSelection();
+ }
+
+ private final class NonRunningAvdFilter implements IAvdFilter {
+
+ private IDevice[] mDevices;
+
+ @Override
+ public void prepare() {
+ mDevices = AndroidDebugBridge.getBridge().getDevices();
+ }
+
+ @Override
+ public boolean accept(AvdInfo avd) {
+ if (mDevices != null) {
+ for (IDevice d : mDevices) {
+ // do not accept running avd's
+ if (avd.getName().equals(d.getAvdName())) {
+ return false;
+ }
+
+ // only accept avd's that can actually run the project
+ AvdCompatibility.Compatibility c =
+ AvdCompatibility.canRun(avd, mProjectTarget, mMinApiVersion);
+ return (c == AvdCompatibility.Compatibility.NO) ? false : true;
+ }
+ }
+
+ return true;
+ }
+
+ @Override
+ public void cleanup() {
+ mDevices = null;
+ }
+ }
+
+ /**
+ * Refills the AVD list keeping the current selection.
+ */
+ private void refillAvdList(boolean reloadAvds) {
+ // save the current selection
+ AvdInfo selected = mPreferredAvdSelector.getSelected();
+
+ // disable selection change.
+ mDisableAvdSelectionChange = true;
+
+ // refresh the list
+ mPreferredAvdSelector.refresh(false);
+
+ // attempt to reselect the proper avd if needed
+ if (selected != null) {
+ if (mPreferredAvdSelector.setSelection(selected) == false) {
+ // looks like the selection is lost. this can happen if an emulator
+ // running the AVD that was selected was launched from outside of Eclipse).
+ mResponse.setAvdToLaunch(null);
+ enableOkButton();
+ }
+ }
+
+ // enable the selection change
+ mDisableAvdSelectionChange = false;
+ }
+}
+