diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/DeviceChooserDialog.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/DeviceChooserDialog.java index 3bc68fea9..6813d0b9e 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/DeviceChooserDialog.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/DeviceChooserDialog.java @@ -26,13 +26,12 @@ import com.android.ddmuilib.ImageHelper; import com.android.ddmuilib.TableHelper; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.internal.sdk.Sdk; -import com.android.ide.eclipse.adt.internal.wizards.actions.AvdManagerAction; import com.android.ide.eclipse.ddms.DdmsPlugin; import com.android.sdklib.IAndroidTarget; -import com.android.sdklib.internal.avd.AvdManager; import com.android.sdklib.internal.avd.AvdManager.AvdInfo; import com.android.sdkuilib.internal.widgets.AvdSelector; -import com.android.sdkuilib.internal.widgets.AvdSelector.SelectionMode; +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; @@ -58,8 +57,6 @@ import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Table; -import java.util.ArrayList; - /** * 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) @@ -91,8 +88,6 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener private final IAndroidTarget mProjectTarget; private final Sdk mSdk; - private AvdInfo[] mFullAvdList; - private Button mDeviceRadioButton; private boolean mDisableAvdSelectionChange = false; @@ -264,6 +259,7 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener mProjectTarget = projectTarget; mSdk = Sdk.getCurrent(); + AndroidDebugBridge.addDeviceChangeListener(this); loadImages(); } @@ -415,24 +411,9 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener offsetComp.setLayout(layout); mPreferredAvdSelector = new AvdSelector(offsetComp, - getNonRunningAvds(false /*reloadAvds*/), - mProjectTarget, - new AvdSelector.IExtraAction() { - public void run() { - AvdManagerAction action = new AvdManagerAction(); - action.run(null); - refillAvdList(true /*reloadAvds*/); - } - - public boolean isEnabled() { - return true; - } - - public String label() { - return "AVD Manager..."; - } - }, - SelectionMode.CHECK); + mSdk.getAvdManager(), + new NonRunningAvdFilter(), + DisplayMode.SIMPLE_SELECTION); mPreferredAvdSelector.setTableHeightHint(100); mPreferredAvdSelector.setEnabled(false); mPreferredAvdSelector.setSelectionListener(new SelectionAdapter() { @@ -594,6 +575,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(false /*reloadAvds*/); // if the changed device is the current selection, @@ -707,50 +689,44 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener handleDeviceSelection(); } - /** - * Returns the list of {@link AvdInfo} that are not already running in an emulator. - */ - private AvdInfo[] getNonRunningAvds(boolean reloadAvds) { - ArrayList list = new ArrayList(); + private final class NonRunningAvdFilter implements IAvdFilter { - // get the full list of Android Virtual Devices - if (reloadAvds || mFullAvdList == null) { - AvdManager avdManager = mSdk.getAvdManager(); - if (avdManager != null) { - mFullAvdList = avdManager.getValidAvds(); - } + private IDevice[] mDevices; + + public void prepare() { + mDevices = AndroidDebugBridge.getBridge().getDevices(); } - // loop through all the Avd and put the one that are not running in the list. - if (mFullAvdList != null) { - IDevice[] devices = AndroidDebugBridge.getBridge().getDevices(); - avdLoop: for (AvdInfo info : mFullAvdList) { - for (IDevice d : devices) { - if (info.getName().equals(d.getAvdName())) { - continue avdLoop; + public boolean accept(AvdInfo avd) { + if (mDevices != null) { + for (IDevice d : mDevices) { + if (mProjectTarget.isCompatibleBaseFor(avd.getTarget()) == false || + avd.getName().equals(d.getAvdName())) { + return false; } } - list.add(info); } + + return true; } - return list.toArray(new AvdInfo[list.size()]); + public void cleanup() { + mDevices = null; + } } /** * Refills the AVD list keeping the current selection. */ private void refillAvdList(boolean reloadAvds) { - AvdInfo[] array = getNonRunningAvds(reloadAvds); - // save the current selection AvdInfo selected = mPreferredAvdSelector.getSelected(); // disable selection change. mDisableAvdSelectionChange = true; - // set the new list in the selector - mPreferredAvdSelector.setAvds(array, mProjectTarget); + // refresh the list + mPreferredAvdSelector.refresh(false); // attempt to reselect the proper avd if needed if (selected != null) { diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/EmulatorConfigTab.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/EmulatorConfigTab.java index 664babe61..4d40c2e9a 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/EmulatorConfigTab.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/EmulatorConfigTab.java @@ -20,14 +20,13 @@ import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.internal.launch.AndroidLaunchConfiguration.TargetMode; import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper; import com.android.ide.eclipse.adt.internal.sdk.Sdk; -import com.android.ide.eclipse.adt.internal.wizards.actions.AvdManagerAction; import com.android.ide.eclipse.ddms.DdmsPlugin; import com.android.prefs.AndroidLocation.AndroidLocationException; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.internal.avd.AvdManager; import com.android.sdklib.internal.avd.AvdManager.AvdInfo; import com.android.sdkuilib.internal.widgets.AvdSelector; -import com.android.sdkuilib.internal.widgets.AvdSelector.SelectionMode; +import com.android.sdkuilib.internal.widgets.AvdSelector.DisplayMode; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; @@ -191,24 +190,12 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab { mPreferredAvdLabel = new Label(offsetComp, SWT.NONE); mPreferredAvdLabel.setText("Select a preferred Android Virtual Device for deployment:"); - mPreferredAvdSelector = new AvdSelector(offsetComp, - null /*avds*/, - new AvdSelector.IExtraAction() { - public void run() { - AvdManagerAction action = new AvdManagerAction(); - action.run(null); - updateAvdList(null); - } - public boolean isEnabled() { - return true; - } - - public String label() { - return "AVD Manager..."; - } - }, - SelectionMode.CHECK); + // create the selector with no manager, we'll reset the manager every time this is + // displayed to ensure we have the latest one (dialog is reused but SDK could have + // been changed in between. + mPreferredAvdSelector = new AvdSelector(offsetComp, null /* avd manager */, + DisplayMode.SIMPLE_CHECK); mPreferredAvdSelector.setTableHeightHint(100); mPreferredAvdSelector.setSelectionListener(new SelectionAdapter() { @Override @@ -322,13 +309,9 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab { 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); + mPreferredAvdSelector.setManager(avdManager); + mPreferredAvdSelector.setFilter(mProjectTarget); + mPreferredAvdSelector.refresh(false); } /* (non-Javadoc) diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/avdmanager/AvdManagerListPage.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/avdmanager/AvdManagerListPage.java index 0ce569c28..9708a0f39 100755 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/avdmanager/AvdManagerListPage.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/avdmanager/AvdManagerListPage.java @@ -27,7 +27,7 @@ import com.android.sdklib.ISdkLog; import com.android.sdklib.internal.avd.AvdManager; import com.android.sdklib.internal.avd.AvdManager.AvdInfo; import com.android.sdkuilib.internal.widgets.AvdSelector; -import com.android.sdkuilib.internal.widgets.AvdSelector.SelectionMode; +import com.android.sdkuilib.internal.widgets.AvdSelector.DisplayMode; import org.eclipse.core.resources.IProject; import org.eclipse.jface.wizard.WizardPage; @@ -162,21 +162,7 @@ class AvdManagerListPage extends WizardPage { } }); - mAvdSelector = new AvdSelector(parent, - SelectionMode.SELECT, - new AvdSelector.IExtraAction() { - public String label() { - return "Delete AVD..."; - } - - public boolean isEnabled() { - return mAvdSelector != null && mAvdSelector.getSelected() != null; - } - - public void run() { - onDelete(); - } - }); + mAvdSelector = new AvdSelector(parent, getAvdManager(), DisplayMode.MANAGER); } /** @@ -430,29 +416,12 @@ class AvdManagerListPage extends WizardPage { * Tries to preserve the selection. */ private void reloadAvdList() { - AvdInfo selected = mAvdSelector.getSelected(); - - AvdManager avdm = getAvdManager(); - AvdInfo[] avds = null; - - // For the AVD manager to reload the list, in case AVDs where created using the - // command line tool. - // The AVD manager may not exist yet, typically when loading the SDK. - if (avdm != null) { - try { - avdm.reloadAvds(); - } catch (AndroidLocationException e) { - AdtPlugin.log(e, "AVD Manager reload failed"); //$NON-NLS-1$ - } - - avds = avdm.getValidAvds(); - } - - mAvdSelector.setAvds(avds, null /*filter*/); + mAvdSelector.refresh(true /* reload */); // Keep the list of known AVD names to check if they exist quickly. however // use the list of all AVDs, including broken ones (unless we don't know their // name). + AvdManager avdm = getAvdManager(); mKnownAvdNames.clear(); if (avdm != null) { for (AvdInfo avd : avdm.getAllAvds()) { @@ -462,14 +431,15 @@ class AvdManagerListPage extends WizardPage { } } } - - mAvdSelector.setSelection(selected); } /** * Triggered when the user selects the "delete" button (the extra action in the selector) * Deletes the currently selected AVD, if any. + * + * This is obsolete. Kept around to reuse the code later in the AvdSelector itself. */ + @Deprecated private void onDelete() { AvdInfo avdInfo = mAvdSelector.getSelected(); AvdManager avdm = getAvdManager(); diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/AvdManagerPage.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/AvdManagerPage.java index da5e2df84..d69ce5f42 100755 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/AvdManagerPage.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/AvdManagerPage.java @@ -16,29 +16,19 @@ package com.android.sdkuilib.internal.repository; -import com.android.sdklib.internal.avd.AvdManager; -import com.android.sdklib.internal.avd.AvdManager.AvdInfo; import com.android.sdkuilib.internal.repository.UpdaterData.ISdkListener; import com.android.sdkuilib.internal.widgets.AvdSelector; -import com.android.sdkuilib.internal.widgets.AvdSelector.SelectionMode; +import com.android.sdkuilib.internal.widgets.AvdSelector.DisplayMode; import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -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.Label; -import java.util.HashSet; - public class AvdManagerPage extends Composite implements ISdkListener { - private Button mRefreshButton; private AvdSelector mAvdSelector; - private final HashSet mKnownAvdNames = new HashSet(); private final UpdaterData mUpdaterData; /** @@ -57,43 +47,12 @@ public class AvdManagerPage extends Composite implements ISdkListener { } private void createContents(Composite parent) { - parent.setLayout(new GridLayout(3, false)); + parent.setLayout(new GridLayout(1, false)); Label label = new Label(parent, SWT.NONE); label.setText("List of existing Android Virtual Devices:"); - label.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, true, false, 2, 1)); - mRefreshButton = new Button(parent, SWT.PUSH); - mRefreshButton.setText("Refresh"); - mRefreshButton.setLayoutData(new GridData(SWT.END, SWT.CENTER, false, false)); - mRefreshButton.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - onRefreshSelected(); //$hide$ - } - }); - - Composite group = new Composite(parent, SWT.NONE); - group.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1)); - GridLayout gl; - group.setLayout(gl = new GridLayout(1, false /*makeColumnsEqualWidth*/)); - gl.marginHeight = gl.marginWidth = 0; - - mAvdSelector = new AvdSelector(group, - SelectionMode.SELECT, - new AvdSelector.IExtraAction() { - public String label() { - return "Delete AVD..."; - } - - public boolean isEnabled() { - return mAvdSelector != null && mAvdSelector.getSelected() != null; - } - - public void run() { - //TODO onDelete(); - } - }); + mAvdSelector = new AvdSelector(parent, mUpdaterData.getAvdManager(), DisplayMode.MANAGER); } @Override @@ -115,48 +74,11 @@ public class AvdManagerPage extends Composite implements ISdkListener { * Called by the constructor right after {@link #createContents(Composite)}. */ private void postCreate() { - reloadAvdList(); - } - - /** - * Reloads the AVD list in the AVD selector. - * Tries to preserve the selection. - */ - private void reloadAvdList() { - AvdInfo selected = mAvdSelector.getSelected(); - - AvdInfo[] avds = null; - - AvdManager manager = mUpdaterData.getAvdManager(); - if (manager != null) { - avds = manager.getValidAvds(); - } - - mAvdSelector.setAvds(avds, null /*filter*/); - - // Keep the list of known AVD names to check if they exist quickly. however - // use the list of all AVDs, including broken ones (unless we don't know their - // name). - mKnownAvdNames.clear(); - if (manager != null) { - for (AvdInfo avd : manager.getAllAvds()) { - String name = avd.getName(); - if (name != null) { - mKnownAvdNames.add(name); - } - } - } - - mAvdSelector.setSelection(selected); + // nothing to be done for now. } public void onSdkChange() { - reloadAvdList(); - } - - private void onRefreshSelected() { - mUpdaterData.reloadAvds(); - reloadAvdList(); + mAvdSelector.refresh(false /*reload*/); } // End of hiding from SWT Designer diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/icons/ImageFactory.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/icons/ImageFactory.java index 44316b692..51d09d5b2 100755 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/icons/ImageFactory.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/icons/ImageFactory.java @@ -18,7 +18,6 @@ package com.android.sdkuilib.internal.repository.icons; import org.eclipse.swt.SWTException; import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.widgets.Display; import java.io.InputStream; @@ -74,7 +73,7 @@ public class ImageFactory { Iterator it = mImages.values().iterator(); while(it.hasNext()) { Image img = it.next(); - if (img != null) { + if (img != null && img.isDisposed() == false) { img.dispose(); } it.remove(); diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java index 205600865..39aea27c1 100644 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java @@ -16,24 +16,28 @@ package com.android.sdkuilib.internal.widgets; +import com.android.prefs.AndroidLocation.AndroidLocationException; import com.android.sdklib.IAndroidTarget; +import com.android.sdklib.internal.avd.AvdManager; import com.android.sdklib.internal.avd.AvdManager.AvdInfo; +import com.android.sdklib.internal.avd.AvdManager.AvdInfo.AvdStatus; +import com.android.sdkuilib.internal.repository.icons.ImageFactory; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ControlAdapter; import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; 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.Image; 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; -import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.TableItem; @@ -42,62 +46,96 @@ import org.eclipse.swt.widgets.TableItem; /** * The AVD selector is a table that is added to the given parent composite. *

- * To use, create it using {@link #AvdSelector(Composite, SelectionMode, IExtraAction)} then + * To use, create it using {@link #AvdSelector(Composite, AvdManager, DisplayMode)} then * call {@link #setSelection(AvdInfo)}, {@link #setSelectionListener(SelectionListener)} * and finally use {@link #getSelected()} to retrieve the selection. */ public final class AvdSelector { - - private AvdInfo[] mAvds; private SelectionListener mSelectionListener; private Table mTable; - private Label mDescription; private static int NUM_COL = 2; - private final SelectionMode mSelectionMode; - private final IExtraAction mExtraAction; - private Button mExtraActionButton; + private final DisplayMode mDisplayMode; + private Button mManagerButton; + private IAvdFilter mTargetFilter; + private AvdManager mManager; + private Image mOkImage; + private Image mBrokenImage; + private ImageFactory mIconFactory; - /** The selection mode, either {@link #SELECT} or {@link #CHECK} */ - public enum SelectionMode { + /** + * The display mode of the AVD Selector. + */ + public static enum DisplayMode { /** + * Manager mode. Invalid AVDs are displayed. Buttons to create/delete AVDs + */ + MANAGER, + + /** + * Non manager mode. Only valid AVDs are displayed. Cannot create/delete AVDs, but + * there is a button to open the AVD Manager. * In the "check" selection mode, checkboxes are displayed on each line * and {@link AvdSelector#getSelected()} returns the line that is checked * even if it is not the currently selected line. Only one line can * be checked at once. */ - CHECK, + SIMPLE_CHECK, + /** + * Non manager mode. Only valid AVDs are displayed. Cannot create/delete AVDs, but + * there is a button to open the AVD Manager. * In the "select" selection mode, there are no checkboxes and * {@link AvdSelector#getSelected()} returns the line currently selected. * Only one line can be selected at once. */ - SELECT + SIMPLE_SELECTION, } /** - * Defines an "extra action" button that can be shown under the AVD Selector. + * A filter to control the whether or not an AVD should be displayed by the AVD Selector. */ - public interface IExtraAction { + public interface IAvdFilter { /** - * Label of the button that will be created. - * This is invoked once when the button is created and cannot be changed later. + * Called before {@link #accept(AvdInfo)} is called for any AVD. */ - public String label(); + void prepare(); /** - * This is invoked just after the selection has changed to update the "enabled" - * state of the action. Implementation should use {@link AvdSelector#getSelected()}. + * Called to decided whether an AVD should be displayed. + * @param avd the AVD to test. + * @return true if the AVD should be displayed. */ - public boolean isEnabled(); + boolean accept(AvdInfo avd); /** - * Run the action, invoked when the button is clicked. - * - * The caller's action is responsible for reloading the AVD list - * using {@link AvdSelector#setAvds(AvdInfo[], IAndroidTarget)}. + * Called after {@link #accept(AvdInfo)} has been called on all the AVDs. */ - public void run(); + void cleanup(); + } + + /** + * Internal implementation of {@link IAvdFilter} to filter out the AVDs that are not + * running an image compatible with a specific target. + */ + private final static class TargetBasedFilter implements IAvdFilter { + private final IAndroidTarget mTarget; + + TargetBasedFilter(IAndroidTarget target) { + mTarget = target; + } + + public void prepare() { + // nothing to prepare + } + + public boolean accept(AvdInfo avd) { + return mTarget.isCompatibleBaseFor(avd.getTarget()); + } + + public void cleanup() { + // nothing to clean up + } } /** @@ -107,20 +145,18 @@ public final class AvdSelector { * {@link IAndroidTarget} will be displayed. * * @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 manager the AVD manager. + * @param filter When non-null, will allow filtering the AVDs to display. * @param extraAction When non-null, displays an extra action button. - * @param selectionMode One of {@link SelectionMode#SELECT} or {@link SelectionMode#CHECK} + * @param displayMode The display mode ({@link DisplayMode}). */ public AvdSelector(Composite parent, - AvdInfo[] avds, - IAndroidTarget filter, - IExtraAction extraAction, - SelectionMode selectionMode) { - mAvds = avds; - mExtraAction = extraAction; - mSelectionMode = selectionMode; + AvdManager manager, + IAvdFilter filter, + DisplayMode displayMode) { + mManager = manager; + mTargetFilter = filter; + mDisplayMode = displayMode; // Layout has 2 columns Composite group = new Composite(parent, SWT.NONE); @@ -129,9 +165,14 @@ public final class AvdSelector { gl.marginHeight = gl.marginWidth = 0; group.setLayoutData(new GridData(GridData.FILL_BOTH)); group.setFont(parent.getFont()); + group.addDisposeListener(new DisposeListener() { + public void widgetDisposed(DisposeEvent arg0) { + mIconFactory.dispose(); + } + }); int style = SWT.FULL_SELECTION | SWT.SINGLE | SWT.BORDER; - if (selectionMode == SelectionMode.CHECK) { + if (displayMode == DisplayMode.SIMPLE_CHECK) { style |= SWT.CHECK; } mTable = new Table(group, style); @@ -139,18 +180,53 @@ public final class AvdSelector { mTable.setLinesVisible(false); setTableHeightHint(0); - mDescription = new Label(group, SWT.WRAP); - mDescription.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + Composite buttons = new Composite(group, SWT.NONE); + buttons.setLayout(gl = new GridLayout(1, false /*makeColumnsEqualWidth*/)); + gl.marginHeight = gl.marginWidth = 0; + buttons.setLayoutData(new GridData(GridData.FILL_VERTICAL)); + buttons.setFont(group.getFont()); - if (extraAction != null) { - mExtraActionButton = new Button(group, SWT.PUSH); - mExtraActionButton.setText(extraAction.label()); - mExtraActionButton.setEnabled(extraAction.isEnabled()); - mExtraActionButton.addSelectionListener(new SelectionAdapter() { + if (displayMode == DisplayMode.MANAGER) { + Button newButton = new Button(buttons, SWT.PUSH | SWT.FLAT); + newButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + newButton.setText("New"); + // TODO: callback for button + + Button deleteButton = new Button(buttons, SWT.PUSH | SWT.FLAT); + deleteButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + deleteButton.setText("Delete"); + // TODO: callback for button + + Label l = new Label(buttons, SWT.SEPARATOR | SWT.HORIZONTAL); + l.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + } + + Button infoButton = new Button(buttons, SWT.PUSH | SWT.FLAT); + infoButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + infoButton.setText("Info..."); + // TODO: callback for button + + Composite padding = new Composite(buttons, SWT.NONE); + padding.setLayoutData(new GridData(GridData.FILL_VERTICAL)); + + Button refreshButton = new Button(buttons, SWT.PUSH | SWT.FLAT); + refreshButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + refreshButton.setText("Resfresh"); + refreshButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent arg0) { + refresh(true); + } + }); + + if (displayMode != DisplayMode.MANAGER) { + mManagerButton = new Button(buttons, SWT.PUSH | SWT.FLAT); + mManagerButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + mManagerButton.setText("Manager..."); + mManagerButton.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { super.widgetSelected(e); - mExtraAction.run(); } }); } @@ -165,41 +241,45 @@ public final class AvdSelector { final TableColumn column3 = new TableColumn(mTable, SWT.NONE); column3.setText("API Level"); + // get some bitmaps. + mIconFactory = new ImageFactory(parent.getDisplay()); + mOkImage = mIconFactory.getImage("accept_icon16.png"); + mBrokenImage = mIconFactory.getImage("reject_icon16.png"); + adjustColumnsWidth(mTable, column0, column1, column2, column3); setupSelectionListener(mTable); - fillTable(mTable, filter); - setupTooltip(mTable); + fillTable(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. - * @param extraAction When non-null, displays an extra action button. - * @param selectionMode One of {@link SelectionMode#SELECT} or {@link SelectionMode#CHECK} + * @param manager the AVD manager. + * @param displayMode The display mode ({@link DisplayMode}). */ - public AvdSelector(Composite parent, - AvdInfo[] avds, - IExtraAction extraAction, - SelectionMode selectionMode) { - this(parent, avds, null /* filter */, extraAction, selectionMode); + public AvdSelector(Composite parent, AvdManager manager, + DisplayMode displayMode) { + this(parent, manager, (IAvdFilter)null /* filter */, displayMode); } /** - * Creates a new SDK Target Selector, and fills it with a list of {@link AvdInfo}. + * Creates a new SDK Target Selector, and fills it with a list of {@link AvdInfo}, filtered + * by an {@link IAndroidTarget}. + *

Only the {@link AvdInfo} able to run applications developed for the given + * {@link IAndroidTarget} will be displayed. * * @param parent The parent composite where the selector will be added. - * @param extraAction When non-null, displays an extra action button. - * @param selectionMode One of {@link SelectionMode#SELECT} or {@link SelectionMode#CHECK} + * @param manager the AVD manager. + * @param filter Only shows the AVDs matching this target (must not be null). + * @param displayMode The display mode ({@link DisplayMode}). */ public AvdSelector(Composite parent, - SelectionMode selectionMode, - IExtraAction extraAction) { - this(parent, null /*avds*/, null /* filter */, extraAction, selectionMode); + AvdManager manager, + IAndroidTarget filter, + DisplayMode displayMode) { + this(parent, manager, new TargetBasedFilter(filter), displayMode); } - /** * Sets the table grid layout data. * @@ -212,41 +292,70 @@ public final class AvdSelector { } data.grabExcessVerticalSpace = true; data.grabExcessHorizontalSpace = true; - data.horizontalSpan = NUM_COL; data.horizontalAlignment = GridData.FILL; data.verticalAlignment = GridData.FILL; mTable.setLayoutData(data); } /** - * Sets a new set of AVD, with an optional filter. + * Refresh the display of Android Virtual Devices. * Tries to keep the selection. *

* 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. + * @param reload if true, the AVD manager will reload the AVD from the disk. + * @throws AndroidLocationException if reload the AVD failed. + * @return false if the reloading failed. This is always true if reload is + * false. */ - public void setAvds(AvdInfo[] avds, IAndroidTarget filter) { + public boolean refresh(boolean reload) { + if (reload) { + try { + mManager.reloadAvds(); + } catch (AndroidLocationException e) { + return false; + } + } AvdInfo selected = getSelected(); - mAvds = avds; - fillTable(mTable, filter); + fillTable(mTable); setSelection(selected); + + return true; } /** - * Returns the list of known AVDs. - *

- * This is not a copy. Callers must not modify this array. + * Sets a new AVD manager + * This does not refresh the display. Call {@link #refresh(boolean)} to do so. + * @param manager the AVD manager. */ - public AvdInfo[] getAvds() { - return mAvds; + public void setManager(AvdManager manager) { + mManager = manager; + } + + /** + * Sets a new AVD filter. + * This does not refresh the display. Call {@link #refresh(boolean)} to do so. + * @param filter An IAvdFilter. If non-null, this will filter out the AVD to not display. + */ + public void setFilter(IAvdFilter filter) { + mTargetFilter = filter; + } + + /** + * Sets a new Android Target-based AVD filter. + * This does not refresh the display. Call {@link #refresh(boolean)} to do so. + * @param target An IAndroidTarget. If non-null, only AVD whose target are compatible with the + * filter target will displayed an available for selection. + */ + public void setFilter(IAndroidTarget target) { + if (target != null) { + mTargetFilter = new TargetBasedFilter(target); + } else { + mTargetFilter = null; + } } /** @@ -281,19 +390,7 @@ public final class AvdSelector { int selIndex = mTable.getSelectionIndex(); int index = 0; for (TableItem i : mTable.getItems()) { - if (mSelectionMode == SelectionMode.SELECT) { - if ((AvdInfo) i.getData() == target) { - found = true; - if (index != selIndex) { - mTable.setSelection(index); - modified = true; - } - break; - } - - index++; - - } else if (mSelectionMode == SelectionMode.CHECK){ + if (mDisplayMode == DisplayMode.SIMPLE_CHECK) { if ((AvdInfo) i.getData() == target) { found = true; if (!i.getChecked()) { @@ -304,6 +401,17 @@ public final class AvdSelector { modified = true; i.setChecked(false); } + } else { + if ((AvdInfo) i.getData() == target) { + found = true; + if (index != selIndex) { + mTable.setSelection(index); + modified = true; + } + break; + } + + index++; } } @@ -311,10 +419,6 @@ public final class AvdSelector { mSelectionListener.widgetSelected(null); } - if (mExtraAction != null && mExtraActionButton != null) { - mExtraActionButton.setEnabled(mExtraAction.isEnabled()); - } - return found; } @@ -324,18 +428,17 @@ public final class AvdSelector { * @return The currently selected item or null. */ public AvdInfo getSelected() { - if (mSelectionMode == SelectionMode.SELECT) { - int selIndex = mTable.getSelectionIndex(); - if (selIndex >= 0) { - return (AvdInfo) mTable.getItem(selIndex).getData(); - } - - } else if (mSelectionMode == SelectionMode.CHECK) { + if (mDisplayMode == DisplayMode.SIMPLE_CHECK) { for (TableItem i : mTable.getItems()) { if (i.getChecked()) { return (AvdInfo) i.getData(); } } + } else { + int selIndex = mTable.getSelectionIndex(); + if (selIndex >= 0) { + return (AvdInfo) mTable.getItem(selIndex).getData(); + } } return null; } @@ -349,7 +452,6 @@ public final class AvdSelector { */ public void setEnabled(boolean enabled) { mTable.setEnabled(enabled); - mDescription.setEnabled(enabled); } /** @@ -368,15 +470,14 @@ public final class AvdSelector { @Override public void controlResized(ControlEvent e) { Rectangle r = table.getClientArea(); - column0.setWidth(r.width * 30 / 100); // 30% + column0.setWidth(r.width * 25 / 100); // 25% column1.setWidth(r.width * 45 / 100); // 45% - column2.setWidth(r.width * 10 / 100); // 10% + column2.setWidth(r.width * 15 / 100); // 15% column3.setWidth(r.width * 15 / 100); // 15% } }); } - /** * Creates a selection listener that will check or uncheck the whole line when * double-clicked (aka "the default selection"). @@ -393,16 +494,11 @@ public final class AvdSelector { if (e.item instanceof TableItem) { TableItem i = (TableItem) e.item; enforceSingleSelection(i); - updateDescription(i); } if (mSelectionListener != null) { mSelectionListener.widgetSelected(e); } - - if (mExtraAction != null && mExtraActionButton != null) { - mExtraActionButton.setEnabled(mExtraAction.isEnabled()); - } } /** @@ -416,20 +512,15 @@ public final class AvdSelector { public void widgetDefaultSelected(SelectionEvent e) { if (e.item instanceof TableItem) { TableItem i = (TableItem) e.item; - if (mSelectionMode == SelectionMode.CHECK) { + if (mDisplayMode == DisplayMode.SIMPLE_CHECK) { i.setChecked(true); } enforceSingleSelection(i); - updateDescription(i); } if (mSelectionListener != null) { mSelectionListener.widgetDefaultSelected(e); } - - if (mExtraAction != null && mExtraActionButton != null) { - mExtraActionButton.setEnabled(mExtraAction.isEnabled()); - } } /** @@ -437,10 +528,7 @@ public final class AvdSelector { * This makes the chekboxes act as radio buttons. */ private void enforceSingleSelection(TableItem item) { - if (mSelectionMode == SelectionMode.SELECT) { - // pass - - } else if (mSelectionMode == SelectionMode.CHECK) { + if (mDisplayMode == DisplayMode.SIMPLE_CHECK) { if (item.getChecked()) { Table parentTable = item.getParent(); for (TableItem i2 : parentTable.getItems()) { @@ -449,6 +537,8 @@ public final class AvdSelector { } } } + } else { + // pass } } }); @@ -464,21 +554,50 @@ public final class AvdSelector { *

  • column 3: sdk version * */ - private void fillTable(final Table table, IAndroidTarget filter) { + private void fillTable(final Table table) { table.removeAll(); - if (mAvds != null && mAvds.length > 0) { + + // get the AVDs + AvdInfo avds[] = null; + if (mManager != null) { + if (mDisplayMode == DisplayMode.MANAGER) { + avds = mManager.getAllAvds(); + } else { + avds = mManager.getValidAvds(); + } + } + + if (avds != null && avds.length > 0) { table.setEnabled(true); - for (AvdInfo avd : mAvds) { - if (filter == null || filter.isCompatibleBaseFor(avd.getTarget())) { + + if (mTargetFilter != null) { + mTargetFilter.prepare(); + } + + for (AvdInfo avd : avds) { + if (mTargetFilter == null || mTargetFilter.accept(avd)) { TableItem item = new TableItem(table, SWT.NONE); item.setData(avd); item.setText(0, avd.getName()); + if (mDisplayMode == DisplayMode.MANAGER) { + item.setImage(0, avd.getStatus() == AvdStatus.OK ? mOkImage : mBrokenImage); + } IAndroidTarget target = avd.getTarget(); - item.setText(1, target.getFullName()); - item.setText(2, target.getApiVersionName()); - item.setText(3, Integer.toString(target.getApiVersionNumber())); + if (target != null) { + item.setText(1, target.getFullName()); + item.setText(2, target.getApiVersionName()); + item.setText(3, Integer.toString(target.getApiVersionNumber())); + } else { + item.setText(1, "?"); + item.setText(2, "?"); + item.setText(3, "?"); + } } } + + if (mTargetFilter != null) { + mTargetFilter.cleanup(); + } } if (table.getItemCount() == 0) { @@ -491,61 +610,4 @@ public final class AvdSelector { item.setText(3, "--"); } } - - /** - * Sets up a tooltip that displays the current item description. - *

    - * Displaying a tooltip over the table looks kind of odd here. Instead we actually - * display the description in a label under the table. - */ - private void setupTooltip(final Table table) { - /* - * Reference: - * http://dev.eclipse.org/viewcvs/index.cgi/org.eclipse.swt.snippets/src/org/eclipse/swt/snippets/Snippet125.java?view=markup - */ - - final Listener listener = new Listener() { - public void handleEvent(Event event) { - - switch(event.type) { - case SWT.KeyDown: - case SWT.MouseExit: - case SWT.MouseDown: - return; - - case SWT.MouseHover: - updateDescription(table.getItem(new Point(event.x, event.y))); - break; - - case SWT.Selection: - if (event.item instanceof TableItem) { - updateDescription((TableItem) event.item); - } - break; - - default: - return; - } - - } - }; - - table.addListener(SWT.Dispose, listener); - table.addListener(SWT.KeyDown, listener); - table.addListener(SWT.MouseMove, listener); - table.addListener(SWT.MouseHover, listener); - } - - /** - * Updates the description label with the path of the item's AVD, if any. - */ - private void updateDescription(TableItem item) { - if (item != null) { - Object data = item.getData(); - if (data instanceof AvdInfo) { - String newTooltip = ((AvdInfo) data).getPath(); - mDescription.setText(newTooltip == null ? "" : newTooltip); //$NON-NLS-1$ - } - } - } }