From e940a1cad7295564fabb0cbd365f3cf47e3b6f32 Mon Sep 17 00:00:00 2001 From: Raphael Date: Thu, 30 Apr 2009 16:10:47 -0700 Subject: [PATCH] ADT #1823896: AVD Manager button in the AVD Selector. Device chooser: avd manager callback + avd list refresh. Device chooser: dialog title. Device launcher tab: avd manager callaback + avd list refresh. --- .../eclipse/adt/launch/DelayedLaunchInfo.java | 2 +- .../adt/launch/DeviceChooserDialog.java | 70 ++++++++++++------- .../eclipse/adt/launch/EmulatorConfigTab.java | 43 ++++++++---- .../avdmanager/AvdManagerListPage.java | 8 +++ .../src/com/android/sdkuilib/AvdSelector.java | 69 ++++++++++++++---- 5 files changed, 138 insertions(+), 54 deletions(-) diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DelayedLaunchInfo.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DelayedLaunchInfo.java index f3bd28a07..893e0959f 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DelayedLaunchInfo.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DelayedLaunchInfo.java @@ -136,7 +136,7 @@ public final class DelayedLaunchInfo { /** * Returns the Android app process name that the debugger should connect to. Typically this is - * the same value as {@link getPackageName} + * the same value as {@link #getPackageName()}. */ public String getDebugPackageName() { if (mDebugPackageName == null) { diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DeviceChooserDialog.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DeviceChooserDialog.java index 1bc07fea1..1b7a63a30 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DeviceChooserDialog.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DeviceChooserDialog.java @@ -27,6 +27,7 @@ import com.android.ddmuilib.ImageHelper; import com.android.ddmuilib.TableHelper; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.sdk.Sdk; +import com.android.ide.eclipse.adt.wizards.actions.AvdManagerAction; import com.android.ide.eclipse.ddms.DdmsPlugin; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.avd.AvdManager; @@ -53,6 +54,7 @@ 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; @@ -89,7 +91,7 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener private final IAndroidTarget mProjectTarget; private final Sdk mSdk; - private final AvdInfo[] mFullAvdList; + private AvdInfo[] mFullAvdList; private Button mDeviceRadioButton; @@ -262,14 +264,6 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener mProjectTarget = projectTarget; mSdk = Sdk.getCurrent(); - // get the full list of Android Virtual Devices - AvdManager avdManager = mSdk.getAvdManager(); - if (avdManager != null) { - mFullAvdList = avdManager.getValidAvds(); - } else { - mFullAvdList = null; - } - loadImages(); } @@ -310,9 +304,16 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener @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)); + Label label = new Label(top, SWT.NONE); + label.setText(String.format("Select a device compatible with target %s.", + mProjectTarget.getFullName())); + mDeviceRadioButton = new Button(top, SWT.RADIO); mDeviceRadioButton.setText("Choose a running Android device"); mDeviceRadioButton.addSelectionListener(new SelectionAdapter() { @@ -344,7 +345,7 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener offsetComp.setLayout(layout); IPreferenceStore store = AdtPlugin.getDefault().getPreferenceStore(); - mDeviceTable = new Table(offsetComp, SWT.SINGLE | SWT.FULL_SELECTION); + mDeviceTable = new Table(offsetComp, SWT.SINGLE | SWT.FULL_SELECTION | SWT.BORDER); GridData gd; mDeviceTable.setLayoutData(gd = new GridData(GridData.FILL_BOTH)); gd.heightHint = 100; @@ -413,7 +414,16 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener layout.marginLeft = 30; offsetComp.setLayout(layout); - mPreferredAvdSelector = new AvdSelector(offsetComp, getNonRunningAvds(), mProjectTarget); + mPreferredAvdSelector = new AvdSelector(offsetComp, + getNonRunningAvds(false /*reloadAvds*/), + mProjectTarget, + new Runnable() { + public void run() { + AvdManagerAction action = new AvdManagerAction(); + action.run(null); + refillAvdList(true /*reloadAvds*/); + } + }); mPreferredAvdSelector.setTableHeightHint(100); mPreferredAvdSelector.setEnabled(false); mPreferredAvdSelector.setSelectionListener(new SelectionAdapter() { @@ -446,7 +456,6 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener } }); - AndroidDebugBridge.addDeviceChangeListener(this); return top; } @@ -529,7 +538,7 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener // update the display of AvdInfo (since it's filtered to only display // non running AVD.) - refillAvdList(); + refillAvdList(false /*reloadAvds*/); } else { // table is disposed, we need to do something. // lets remove ourselves from the listener. @@ -576,7 +585,7 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener // 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(); + refillAvdList(false /*reloadAvds*/); // if the changed device is the current selection, // we update the OK button based on its state. @@ -692,19 +701,28 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener /** * Returns the list of {@link AvdInfo} that are not already running in an emulator. */ - private AvdInfo[] getNonRunningAvds() { + private AvdInfo[] getNonRunningAvds(boolean reloadAvds) { ArrayList list = new ArrayList(); - Device[] devices = AndroidDebugBridge.getBridge().getDevices(); - - // loop through all the Avd and put the one that are not running in the list. - avdLoop: for (AvdInfo info : mFullAvdList) { - for (Device d : devices) { - if (info.getName().equals(d.getAvdName())) { - continue avdLoop; - } + // get the full list of Android Virtual Devices + if (reloadAvds || mFullAvdList == null) { + AvdManager avdManager = mSdk.getAvdManager(); + if (avdManager != null) { + mFullAvdList = avdManager.getValidAvds(); + } + } + + // loop through all the Avd and put the one that are not running in the list. + if (mFullAvdList != null) { + Device[] devices = AndroidDebugBridge.getBridge().getDevices(); + avdLoop: for (AvdInfo info : mFullAvdList) { + for (Device d : devices) { + if (info.getName().equals(d.getAvdName())) { + continue avdLoop; + } + } + list.add(info); } - list.add(info); } return list.toArray(new AvdInfo[list.size()]); @@ -713,8 +731,8 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener /** * Refills the AVD list keeping the current selection. */ - private void refillAvdList() { - AvdInfo[] array = getNonRunningAvds(); + private void refillAvdList(boolean reloadAvds) { + AvdInfo[] array = getNonRunningAvds(reloadAvds); // save the current selection AvdInfo selected = mPreferredAvdSelector.getFirstSelected(); diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/EmulatorConfigTab.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/EmulatorConfigTab.java index bba712693..48a6b59b2 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/EmulatorConfigTab.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/EmulatorConfigTab.java @@ -19,6 +19,7 @@ package com.android.ide.eclipse.adt.launch; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.launch.AndroidLaunchConfiguration.TargetMode; import com.android.ide.eclipse.adt.sdk.Sdk; +import com.android.ide.eclipse.adt.wizards.actions.AvdManagerAction; import com.android.ide.eclipse.common.project.BaseProjectHelper; import com.android.ide.eclipse.ddms.DdmsPlugin; import com.android.prefs.AndroidLocation.AndroidLocationException; @@ -92,6 +93,8 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab { private Label mPreferredAvdLabel; + private IAndroidTarget mProjectTarget; + /** * Returns the emulator ready speed option value. * @param value The index of the combo selection. @@ -187,8 +190,15 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab { mPreferredAvdLabel = new Label(offsetComp, SWT.NONE); mPreferredAvdLabel.setText("Select a preferred Android Virtual Device for deployment:"); - AvdInfo[] avds = new AvdInfo[0]; - mPreferredAvdSelector = new AvdSelector(offsetComp, avds); + mPreferredAvdSelector = new AvdSelector(offsetComp, + null /*avds*/, + new Runnable() { + public void run() { + AvdManagerAction action = new AvdManagerAction(); + action.run(null); + updateAvdList(null); + } + }); mPreferredAvdSelector.setTableHeightHint(100); mPreferredAvdSelector.setSelectionListener(new SelectionAdapter() { @Override @@ -296,6 +306,21 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab { return DdmsPlugin.getImageLoader().loadImage("emulator.png", null); //$NON-NLS-1$ } + + private void updateAvdList(AvdManager avdManager) { + if (avdManager == null) { + avdManager = Sdk.getCurrent().getAvdManager(); + } + + AvdInfo[] avds = null; + // no project? we don't want to display any "compatible" AVDs. + if (avdManager != null && mProjectTarget != null) { + avds = avdManager.getValidAvds(); + } + + mPreferredAvdSelector.setAvds(avds, mProjectTarget); + } + /* (non-Javadoc) * @see org.eclipse.debug.ui.ILaunchConfigurationTab#initializeFrom(org.eclipse.debug.core.ILaunchConfiguration) */ @@ -336,19 +361,11 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab { } // update the AVD list - AvdInfo[] avds = null; - if (avdManager != null) { - avds = avdManager.getValidAvds(); + if (project != null) { + mProjectTarget = Sdk.getCurrent().getTarget(project); } - IAndroidTarget projectTarget = null; - if (project != null) { - projectTarget = Sdk.getCurrent().getTarget(project); - } else { - avds = null; // no project? we don't want to display any "compatible" AVDs. - } - - mPreferredAvdSelector.setAvds(avds, projectTarget); + updateAvdList(avdManager); stringValue = ""; try { diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/avdmanager/AvdManagerListPage.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/avdmanager/AvdManagerListPage.java index 6444608e5..d569b6917 100755 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/avdmanager/AvdManagerListPage.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/avdmanager/AvdManagerListPage.java @@ -445,6 +445,14 @@ class AvdManagerListPage extends WizardPage { AvdManager avdm = getAvdManager(); + // For the AVD manager to reload the list, in case AVDs where created using the + // command line tool. + try { + avdm.reloadAvds(); + } catch (AndroidLocationException e) { + AdtPlugin.log(e, "AVD Manager reload failed"); //$NON-NLS-1$ + } + AvdInfo[] avds = avdm == null ? null : avdm.getValidAvds(); mAvdSelector.setAvds(avds, null /*filter*/); diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/AvdSelector.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/AvdSelector.java index 729741b67..6ccc66bbd 100644 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/AvdSelector.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/AvdSelector.java @@ -22,12 +22,14 @@ import com.android.sdklib.avd.AvdManager.AvdInfo; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ControlAdapter; import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; 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.Event; import org.eclipse.swt.widgets.Label; @@ -51,6 +53,8 @@ public final class AvdSelector { private Table mTable; private Label mDescription; + private static int NUM_COL = 2; + /** * Creates a new SDK Target Selector, and fills it with a list of {@link AvdInfo}, filtered * by a {@link IAndroidTarget}. @@ -59,30 +63,44 @@ public final class AvdSelector { * * @param parent The parent composite where the selector will be added. * @param avds The list of AVDs. This is not copied, the caller must not modify. + * It can be null. + * @param filter When non-null, will display only the AVDs matching this target. + * @param avdManagerAction A runnable to associate with an "AVD Manager" button. This button + * is hidden if null is passed. The caller's action is responsible for reloading + * the AVD list using {@link #setAvds(AvdInfo[], IAndroidTarget)}. */ - public AvdSelector(Composite parent, AvdInfo[] avds, IAndroidTarget filter) { + public AvdSelector(Composite parent, + AvdInfo[] avds, + IAndroidTarget filter, + final Runnable avdManagerAction) { mAvds = avds; - // Layout has 1 column + // Layout has 2 columns Composite group = new Composite(parent, SWT.NONE); - group.setLayout(new GridLayout()); + group.setLayout(new GridLayout(NUM_COL, false /*makeColumnsEqualWidth*/)); group.setLayoutData(new GridData(GridData.FILL_BOTH)); group.setFont(parent.getFont()); mTable = new Table(group, SWT.CHECK | SWT.FULL_SELECTION | SWT.SINGLE | SWT.BORDER); mTable.setHeaderVisible(true); mTable.setLinesVisible(false); - - GridData data = new GridData(); - data.grabExcessVerticalSpace = true; - data.grabExcessHorizontalSpace = true; - data.horizontalAlignment = GridData.FILL; - data.verticalAlignment = GridData.FILL; - mTable.setLayoutData(data); + setTableHeightHint(0); mDescription = new Label(group, SWT.WRAP); mDescription.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + if (avdManagerAction != null) { + Button avdManagerButton = new Button(group, SWT.PUSH); + avdManagerButton.setText("AVD Manager..."); + avdManagerButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + super.widgetSelected(e); + avdManagerAction.run(); + } + }); + } + // create the table columns final TableColumn column0 = new TableColumn(mTable, SWT.NONE); column0.setText("AVD Name"); @@ -98,23 +116,45 @@ public final class AvdSelector { fillTable(mTable, filter); setupTooltip(mTable); } - + /** * Creates a new SDK Target Selector, and fills it with a list of {@link AvdInfo}. * * @param parent The parent composite where the selector will be added. * @param avds The list of AVDs. This is not copied, the caller must not modify. + * It can be null. */ public AvdSelector(Composite parent, AvdInfo[] avds) { - this(parent, avds, null /* filter */); + this(parent, avds, null /* filter */, null /* avdManagerAction */); } - + /** + * Creates a new SDK Target Selector, and fills it with a list of {@link AvdInfo}. + * + * @param parent The parent composite where the selector will be added. + * @param avds The list of AVDs. This is not copied, the caller must not modify. + * It can be null. + * @param avdManagerAction A runnable to associate with an "AVD Manager" button. This button + * is hidden if null is passed. The caller's action is responsible for reloading + * the AVD list using {@link #setAvds(AvdInfo[], IAndroidTarget)}. + */ + public AvdSelector(Composite parent, AvdInfo[] avds, Runnable avdManagerAction) { + this(parent, avds, null /* filter */, avdManagerAction); + } + + /** + * Sets the table grid layout data. + * + * @param heightHint If > 0, tthe height hint is set to the requested value. + */ public void setTableHeightHint(int heightHint) { GridData data = new GridData(); - data.heightHint = heightHint; + if (heightHint > 0) { + data.heightHint = heightHint; + } data.grabExcessVerticalSpace = true; data.grabExcessHorizontalSpace = true; + data.horizontalSpan = NUM_COL; data.horizontalAlignment = GridData.FILL; data.verticalAlignment = GridData.FILL; mTable.setLayoutData(data); @@ -125,6 +165,7 @@ public final class AvdSelector { *

This must be called from the UI thread. * * @param avds The list of AVDs. This is not copied, the caller must not modify. + * It can be null. * @param filter An IAndroidTarget. If non-null, only AVD whose target are compatible with the * filter target will displayed an available for selection. */