OSDN Git Service

ADT #1823896: AVD Manager button in the AVD Selector.
authorRaphael <raphael@google.com>
Thu, 30 Apr 2009 23:10:47 +0000 (16:10 -0700)
committerRaphael <raphael@google.com>
Fri, 1 May 2009 00:14:58 +0000 (17:14 -0700)
Device chooser: avd manager callback + avd list refresh.
Device chooser: dialog title.
Device launcher tab: avd manager callaback + avd list refresh.

eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DelayedLaunchInfo.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DeviceChooserDialog.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/EmulatorConfigTab.java
eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/avdmanager/AvdManagerListPage.java
sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/AvdSelector.java

index f3bd28a..893e095 100644 (file)
@@ -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) {
index 1bc07fe..1b7a63a 100644 (file)
@@ -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<AvdInfo> list = new ArrayList<AvdInfo>();
         
-        Device[] devices = AndroidDebugBridge.getBridge().getDevices();
-        
+        // 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.
-        avdLoop: for (AvdInfo info : mFullAvdList) {
-            for (Device d : devices) {
-                if (info.getName().equals(d.getAvdName())) {
-                    continue avdLoop;
+        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();
index bba7126..48a6b59 100644 (file)
@@ -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();
-        }
-
-        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.
+            mProjectTarget = Sdk.getCurrent().getTarget(project);
         }
-        
-        mPreferredAvdSelector.setAvds(avds, projectTarget);
+
+        updateAvdList(avdManager);
 
         stringValue = "";
         try {
index 6444608..d569b69 100755 (executable)
@@ -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*/);
 
index 729741b..6ccc66b 100644 (file)
@@ -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 <em>not</em> 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 <em>not</em> 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 <em>not</em> 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 {
      * <p/>This must be called from the UI thread.
      * 
      * @param avds The list of AVDs. This is <em>not</em> 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.
      */