Home | History | Annotate | Download | only in launch
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Eclipse Public License, Version 1.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.eclipse.org/org/documents/epl-v10.php
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.ide.eclipse.adt.internal.launch;
     18 
     19 import com.android.ddmlib.AndroidDebugBridge;
     20 import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener;
     21 import com.android.ddmlib.Client;
     22 import com.android.ddmlib.IDevice;
     23 import com.android.ddmlib.IDevice.DeviceState;
     24 import com.android.ddmuilib.ImageLoader;
     25 import com.android.ddmuilib.TableHelper;
     26 import com.android.ide.eclipse.adt.internal.editors.IconFactory;
     27 import com.android.ide.eclipse.adt.internal.sdk.AdtConsoleSdkLog;
     28 import com.android.ide.eclipse.adt.internal.sdk.Sdk;
     29 import com.android.ide.eclipse.ddms.DdmsPlugin;
     30 import com.android.sdklib.AndroidVersion;
     31 import com.android.sdklib.IAndroidTarget;
     32 import com.android.sdklib.internal.avd.AvdInfo;
     33 import com.android.sdkuilib.internal.widgets.AvdSelector;
     34 import com.android.sdkuilib.internal.widgets.AvdSelector.DisplayMode;
     35 import com.android.sdkuilib.internal.widgets.AvdSelector.IAvdFilter;
     36 
     37 import org.eclipse.jface.dialogs.Dialog;
     38 import org.eclipse.jface.dialogs.IDialogConstants;
     39 import org.eclipse.jface.viewers.ILabelProviderListener;
     40 import org.eclipse.jface.viewers.IStructuredContentProvider;
     41 import org.eclipse.jface.viewers.ITableLabelProvider;
     42 import org.eclipse.jface.viewers.StructuredSelection;
     43 import org.eclipse.jface.viewers.TableViewer;
     44 import org.eclipse.jface.viewers.Viewer;
     45 import org.eclipse.swt.SWT;
     46 import org.eclipse.swt.SWTException;
     47 import org.eclipse.swt.events.SelectionAdapter;
     48 import org.eclipse.swt.events.SelectionEvent;
     49 import org.eclipse.swt.graphics.Image;
     50 import org.eclipse.swt.layout.GridData;
     51 import org.eclipse.swt.layout.GridLayout;
     52 import org.eclipse.swt.widgets.Button;
     53 import org.eclipse.swt.widgets.Composite;
     54 import org.eclipse.swt.widgets.Control;
     55 import org.eclipse.swt.widgets.Display;
     56 import org.eclipse.swt.widgets.Label;
     57 import org.eclipse.swt.widgets.Shell;
     58 import org.eclipse.swt.widgets.Table;
     59 
     60 /**
     61  * A dialog that lets the user choose a device to deploy an application.
     62  * The user can either choose an exiting running device (including running emulators)
     63  * or start a new emulator using an Android Virtual Device configuration that matches
     64  * the current project.
     65  */
     66 public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener {
     67 
     68     private final static int ICON_WIDTH = 16;
     69 
     70     private Table mDeviceTable;
     71     private TableViewer mViewer;
     72     private AvdSelector mPreferredAvdSelector;
     73 
     74     private Image mDeviceImage;
     75     private Image mEmulatorImage;
     76     private Image mMatchImage;
     77     private Image mNoMatchImage;
     78     private Image mWarningImage;
     79 
     80     private final DeviceChooserResponse mResponse;
     81     private final String mPackageName;
     82     private final IAndroidTarget mProjectTarget;
     83     private final Sdk mSdk;
     84 
     85     private Button mDeviceRadioButton;
     86 
     87     private boolean mDisableAvdSelectionChange = false;
     88 
     89     /**
     90      * Basic Content Provider for a table full of {@link IDevice} objects. The input is
     91      * a {@link AndroidDebugBridge}.
     92      */
     93     private static class ContentProvider implements IStructuredContentProvider {
     94         public Object[] getElements(Object inputElement) {
     95             if (inputElement instanceof AndroidDebugBridge) {
     96                 return ((AndroidDebugBridge)inputElement).getDevices();
     97             }
     98 
     99             return new Object[0];
    100         }
    101 
    102         public void dispose() {
    103             // pass
    104         }
    105 
    106         public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
    107             // pass
    108         }
    109     }
    110 
    111 
    112     /**
    113      * A Label Provider for the {@link TableViewer} in {@link DeviceChooserDialog}.
    114      * It provides labels and images for {@link IDevice} objects.
    115      */
    116     private class LabelProvider implements ITableLabelProvider {
    117 
    118         public Image getColumnImage(Object element, int columnIndex) {
    119             if (element instanceof IDevice) {
    120                 IDevice device = (IDevice)element;
    121                 switch (columnIndex) {
    122                     case 0:
    123                         return device.isEmulator() ? mEmulatorImage : mDeviceImage;
    124 
    125                     case 2:
    126                         // check for compatibility.
    127                         if (device.isEmulator() == false) { // physical device
    128                             // get the version of the device
    129                             AndroidVersion deviceVersion = Sdk.getDeviceVersion(device);
    130                             if (deviceVersion == null) {
    131                                 return mWarningImage;
    132                             } else {
    133                                 if (deviceVersion.canRun(mProjectTarget.getVersion()) == false) {
    134                                     return mNoMatchImage;
    135                                 }
    136 
    137                                 // if the project is compiling against an add-on,
    138                                 // the optional API may be missing from the device.
    139                                 return mProjectTarget.isPlatform() ?
    140                                         mMatchImage : mWarningImage;
    141                             }
    142                         } else {
    143                             // get the AvdInfo
    144                             AvdInfo info = mSdk.getAvdManager().getAvd(device.getAvdName(),
    145                                     true /*validAvdOnly*/);
    146                             if (info == null) {
    147                                 return mWarningImage;
    148                             }
    149                             return mProjectTarget.canRunOn(info.getTarget()) ?
    150                                     mMatchImage : mNoMatchImage;
    151                         }
    152                 }
    153             }
    154 
    155             return null;
    156         }
    157 
    158         public String getColumnText(Object element, int columnIndex) {
    159             if (element instanceof IDevice) {
    160                 IDevice device = (IDevice)element;
    161                 switch (columnIndex) {
    162                     case 0:
    163                         return device.getSerialNumber();
    164                     case 1:
    165                         if (device.isEmulator()) {
    166                             return device.getAvdName();
    167                         } else {
    168                             return "N/A"; // devices don't have AVD names.
    169                         }
    170                     case 2:
    171                         if (device.isEmulator()) {
    172                             AvdInfo info = mSdk.getAvdManager().getAvd(device.getAvdName(),
    173                                     true /*validAvdOnly*/);
    174                             if (info == null) {
    175                                 return "?";
    176                             }
    177                             return info.getTarget().getFullName();
    178                         } else {
    179                             String deviceBuild = device.getProperty(IDevice.PROP_BUILD_VERSION);
    180                             if (deviceBuild == null) {
    181                                 return "unknown";
    182                             }
    183                             return deviceBuild;
    184                         }
    185                     case 3:
    186                         String debuggable = device.getProperty(IDevice.PROP_DEBUGGABLE);
    187                         if (debuggable != null && debuggable.equals("1")) { //$NON-NLS-1$
    188                             return "Yes";
    189                         } else {
    190                             return "";
    191                         }
    192                     case 4:
    193                         return getStateString(device);
    194                 }
    195             }
    196 
    197             return null;
    198         }
    199 
    200         public void addListener(ILabelProviderListener listener) {
    201             // pass
    202         }
    203 
    204         public void dispose() {
    205             // pass
    206         }
    207 
    208         public boolean isLabelProperty(Object element, String property) {
    209             // pass
    210             return false;
    211         }
    212 
    213         public void removeListener(ILabelProviderListener listener) {
    214             // pass
    215         }
    216     }
    217 
    218     public static class DeviceChooserResponse {
    219         private AvdInfo mAvdToLaunch;
    220         private IDevice mDeviceToUse;
    221 
    222         public void setDeviceToUse(IDevice d) {
    223             mDeviceToUse = d;
    224             mAvdToLaunch = null;
    225         }
    226 
    227         public void setAvdToLaunch(AvdInfo avd) {
    228             mAvdToLaunch = avd;
    229             mDeviceToUse = null;
    230         }
    231 
    232         public IDevice getDeviceToUse() {
    233             return mDeviceToUse;
    234         }
    235 
    236         public AvdInfo getAvdToLaunch() {
    237             return mAvdToLaunch;
    238         }
    239     }
    240 
    241     public DeviceChooserDialog(Shell parent, DeviceChooserResponse response, String packageName,
    242             IAndroidTarget projectTarget) {
    243         super(parent);
    244         mResponse = response;
    245         mPackageName = packageName;
    246         mProjectTarget = projectTarget;
    247         mSdk = Sdk.getCurrent();
    248 
    249         AndroidDebugBridge.addDeviceChangeListener(this);
    250         loadImages();
    251     }
    252 
    253     private void cleanup() {
    254         // done listening.
    255         AndroidDebugBridge.removeDeviceChangeListener(this);
    256     }
    257 
    258     @Override
    259     protected void okPressed() {
    260         cleanup();
    261         super.okPressed();
    262     }
    263 
    264     @Override
    265     protected void cancelPressed() {
    266         cleanup();
    267         super.cancelPressed();
    268     }
    269 
    270     @Override
    271     protected Control createContents(Composite parent) {
    272         Control content = super.createContents(parent);
    273 
    274         // this must be called after createContents() has happened so that the
    275         // ok button has been created (it's created after the call to createDialogArea)
    276         updateDefaultSelection();
    277 
    278         return content;
    279     }
    280 
    281 
    282     @Override
    283     protected Control createDialogArea(Composite parent) {
    284         // set dialog title
    285         getShell().setText("Android Device Chooser");
    286 
    287         Composite top = new Composite(parent, SWT.NONE);
    288         top.setLayout(new GridLayout(1, true));
    289 
    290         Label label = new Label(top, SWT.NONE);
    291         label.setText(String.format("Select a device compatible with target %s.",
    292                 mProjectTarget.getFullName()));
    293 
    294         mDeviceRadioButton = new Button(top, SWT.RADIO);
    295         mDeviceRadioButton.setText("Choose a running Android device");
    296         mDeviceRadioButton.addSelectionListener(new SelectionAdapter() {
    297             @Override
    298             public void widgetSelected(SelectionEvent e) {
    299                 boolean deviceMode = mDeviceRadioButton.getSelection();
    300 
    301                 mDeviceTable.setEnabled(deviceMode);
    302                 mPreferredAvdSelector.setEnabled(!deviceMode);
    303 
    304                 if (deviceMode) {
    305                     handleDeviceSelection();
    306                 } else {
    307                     mResponse.setAvdToLaunch(mPreferredAvdSelector.getSelected());
    308                 }
    309 
    310                 enableOkButton();
    311             }
    312         });
    313         mDeviceRadioButton.setSelection(true);
    314 
    315 
    316         // offset the selector from the radio button
    317         Composite offsetComp = new Composite(top, SWT.NONE);
    318         offsetComp.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    319         GridLayout layout = new GridLayout(1, false);
    320         layout.marginRight = layout.marginHeight = 0;
    321         layout.marginLeft = 30;
    322         offsetComp.setLayout(layout);
    323 
    324         mDeviceTable = new Table(offsetComp, SWT.SINGLE | SWT.FULL_SELECTION | SWT.BORDER);
    325         GridData gd;
    326         mDeviceTable.setLayoutData(gd = new GridData(GridData.FILL_BOTH));
    327         gd.heightHint = 100;
    328 
    329         mDeviceTable.setHeaderVisible(true);
    330         mDeviceTable.setLinesVisible(true);
    331 
    332         TableHelper.createTableColumn(mDeviceTable, "Serial Number",
    333                 SWT.LEFT, "AAA+AAAAAAAAAAAAAAAAAAA", //$NON-NLS-1$
    334                 null /* prefs name */, null /* prefs store */);
    335 
    336         TableHelper.createTableColumn(mDeviceTable, "AVD Name",
    337                 SWT.LEFT, "AAAAAAAAAAAAAAAAAAA", //$NON-NLS-1$
    338                 null /* prefs name */, null /* prefs store */);
    339 
    340         TableHelper.createTableColumn(mDeviceTable, "Target",
    341                 SWT.LEFT, "AAA+Android 9.9.9", //$NON-NLS-1$
    342                 null /* prefs name */, null /* prefs store */);
    343 
    344         TableHelper.createTableColumn(mDeviceTable, "Debug",
    345                 SWT.LEFT, "Debug", //$NON-NLS-1$
    346                 null /* prefs name */, null /* prefs store */);
    347 
    348         TableHelper.createTableColumn(mDeviceTable, "State",
    349                 SWT.LEFT, "bootloader", //$NON-NLS-1$
    350                 null /* prefs name */, null /* prefs store */);
    351 
    352         // create the viewer for it
    353         mViewer = new TableViewer(mDeviceTable);
    354         mViewer.setContentProvider(new ContentProvider());
    355         mViewer.setLabelProvider(new LabelProvider());
    356         mViewer.setInput(AndroidDebugBridge.getBridge());
    357 
    358         mDeviceTable.addSelectionListener(new SelectionAdapter() {
    359             /**
    360              * Handles single-click selection on the device selector.
    361              * {@inheritDoc}
    362              */
    363             @Override
    364             public void widgetSelected(SelectionEvent e) {
    365                 handleDeviceSelection();
    366             }
    367 
    368             /**
    369              * Handles double-click selection on the device selector.
    370              * Note that the single-click handler will probably already have been called.
    371              * {@inheritDoc}
    372              */
    373             @Override
    374             public void widgetDefaultSelected(SelectionEvent e) {
    375                 handleDeviceSelection();
    376                 if (isOkButtonEnabled()) {
    377                     okPressed();
    378                 }
    379             }
    380         });
    381 
    382         Button radio2 = new Button(top, SWT.RADIO);
    383         radio2.setText("Launch a new Android Virtual Device");
    384 
    385         // offset the selector from the radio button
    386         offsetComp = new Composite(top, SWT.NONE);
    387         offsetComp.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
    388         layout = new GridLayout(1, false);
    389         layout.marginRight = layout.marginHeight = 0;
    390         layout.marginLeft = 30;
    391         offsetComp.setLayout(layout);
    392 
    393         mPreferredAvdSelector = new AvdSelector(offsetComp,
    394                 mSdk.getSdkLocation(),
    395                 mSdk.getAvdManager(),
    396                 new NonRunningAvdFilter(),
    397                 DisplayMode.SIMPLE_SELECTION,
    398                 new AdtConsoleSdkLog());
    399         mPreferredAvdSelector.setTableHeightHint(100);
    400         mPreferredAvdSelector.setEnabled(false);
    401         mPreferredAvdSelector.setSelectionListener(new SelectionAdapter() {
    402             /**
    403              * Handles single-click selection on the AVD selector.
    404              * {@inheritDoc}
    405              */
    406             @Override
    407             public void widgetSelected(SelectionEvent e) {
    408                 if (mDisableAvdSelectionChange == false) {
    409                     mResponse.setAvdToLaunch(mPreferredAvdSelector.getSelected());
    410                     enableOkButton();
    411                 }
    412             }
    413 
    414             /**
    415              * Handles double-click selection on the AVD selector.
    416              *
    417              * Note that the single-click handler will probably already have been called
    418              * but the selected item can have changed in between.
    419              *
    420              * {@inheritDoc}
    421              */
    422             @Override
    423             public void widgetDefaultSelected(SelectionEvent e) {
    424                 widgetSelected(e);
    425                 if (isOkButtonEnabled()) {
    426                     okPressed();
    427                 }
    428             }
    429         });
    430 
    431 
    432         return top;
    433     }
    434 
    435     private void loadImages() {
    436         ImageLoader ddmUiLibLoader = ImageLoader.getDdmUiLibLoader();
    437         Display display = DdmsPlugin.getDisplay();
    438         IconFactory factory = IconFactory.getInstance();
    439 
    440         if (mDeviceImage == null) {
    441             mDeviceImage = ddmUiLibLoader.loadImage(display,
    442                     "device.png", //$NON-NLS-1$
    443                     ICON_WIDTH, ICON_WIDTH,
    444                     display.getSystemColor(SWT.COLOR_RED));
    445         }
    446         if (mEmulatorImage == null) {
    447             mEmulatorImage = ddmUiLibLoader.loadImage(display,
    448                     "emulator.png", ICON_WIDTH, ICON_WIDTH, //$NON-NLS-1$
    449                     display.getSystemColor(SWT.COLOR_BLUE));
    450         }
    451 
    452         if (mMatchImage == null) {
    453             mMatchImage = factory.getIcon("match", //$NON-NLS-1$
    454                     IconFactory.COLOR_GREEN,
    455                     IconFactory.SHAPE_DEFAULT);
    456         }
    457 
    458         if (mNoMatchImage == null) {
    459             mNoMatchImage = factory.getIcon("error", //$NON-NLS-1$
    460                     IconFactory.COLOR_RED,
    461                     IconFactory.SHAPE_DEFAULT);
    462         }
    463 
    464         if (mWarningImage == null) {
    465             mWarningImage = factory.getIcon("warning", //$NON-NLS-1$
    466                     SWT.COLOR_YELLOW,
    467                     IconFactory.SHAPE_DEFAULT);
    468         }
    469 
    470     }
    471 
    472     /**
    473      * Returns a display string representing the state of the device.
    474      * @param d the device
    475      */
    476     private static String getStateString(IDevice d) {
    477         DeviceState deviceState = d.getState();
    478         if (deviceState == DeviceState.ONLINE) {
    479             return "Online";
    480         } else if (deviceState == DeviceState.OFFLINE) {
    481             return "Offline";
    482         } else if (deviceState == DeviceState.BOOTLOADER) {
    483             return "Bootloader";
    484         }
    485 
    486         return "??";
    487     }
    488 
    489     /**
    490      * Sent when the a device is connected to the {@link AndroidDebugBridge}.
    491      * <p/>
    492      * This is sent from a non UI thread.
    493      * @param device the new device.
    494      *
    495      * @see IDeviceChangeListener#deviceConnected(IDevice)
    496      */
    497     public void deviceConnected(IDevice device) {
    498         final DeviceChooserDialog dialog = this;
    499         exec(new Runnable() {
    500             public void run() {
    501                 if (mDeviceTable.isDisposed() == false) {
    502                     // refresh all
    503                     mViewer.refresh();
    504 
    505                     // update the selection
    506                     updateDefaultSelection();
    507 
    508                     // update the display of AvdInfo (since it's filtered to only display
    509                     // non running AVD.)
    510                     refillAvdList(false /*reloadAvds*/);
    511                 } else {
    512                     // table is disposed, we need to do something.
    513                     // lets remove ourselves from the listener.
    514                     AndroidDebugBridge.removeDeviceChangeListener(dialog);
    515                 }
    516 
    517             }
    518         });
    519     }
    520 
    521     /**
    522      * Sent when the a device is connected to the {@link AndroidDebugBridge}.
    523      * <p/>
    524      * This is sent from a non UI thread.
    525      * @param device the new device.
    526      *
    527      * @see IDeviceChangeListener#deviceDisconnected(IDevice)
    528      */
    529     public void deviceDisconnected(IDevice device) {
    530         deviceConnected(device);
    531     }
    532 
    533     /**
    534      * Sent when a device data changed, or when clients are started/terminated on the device.
    535      * <p/>
    536      * This is sent from a non UI thread.
    537      * @param device the device that was updated.
    538      * @param changeMask the mask indicating what changed.
    539      *
    540      * @see IDeviceChangeListener#deviceChanged(IDevice, int)
    541      */
    542     public void deviceChanged(final IDevice device, int changeMask) {
    543         if ((changeMask & (IDevice.CHANGE_STATE | IDevice.CHANGE_BUILD_INFO)) != 0) {
    544             final DeviceChooserDialog dialog = this;
    545             exec(new Runnable() {
    546                 public void run() {
    547                     if (mDeviceTable.isDisposed() == false) {
    548                         // refresh the device
    549                         mViewer.refresh(device);
    550 
    551                         // update the defaultSelection.
    552                         updateDefaultSelection();
    553 
    554                         // update the display of AvdInfo (since it's filtered to only display
    555                         // non running AVD). This is done on deviceChanged because the avd name
    556                         // of a (emulator) device may be updated as the emulator boots.
    557 
    558                         refillAvdList(false /*reloadAvds*/);
    559 
    560                         // if the changed device is the current selection,
    561                         // we update the OK button based on its state.
    562                         if (device == mResponse.getDeviceToUse()) {
    563                             enableOkButton();
    564                         }
    565 
    566                     } else {
    567                         // table is disposed, we need to do something.
    568                         // lets remove ourselves from the listener.
    569                         AndroidDebugBridge.removeDeviceChangeListener(dialog);
    570                     }
    571                 }
    572             });
    573         }
    574     }
    575 
    576     /**
    577      * Returns whether the dialog is in "device" mode (true), or in "avd" mode (false).
    578      */
    579     private boolean isDeviceMode() {
    580         return mDeviceRadioButton.getSelection();
    581     }
    582 
    583     /**
    584      * Enables or disables the OK button of the dialog based on various selections in the dialog.
    585      */
    586     private void enableOkButton() {
    587         Button okButton = getButton(IDialogConstants.OK_ID);
    588 
    589         if (isDeviceMode()) {
    590             okButton.setEnabled(mResponse.getDeviceToUse() != null &&
    591                     mResponse.getDeviceToUse().isOnline());
    592         } else {
    593             okButton.setEnabled(mResponse.getAvdToLaunch() != null);
    594         }
    595     }
    596 
    597     /**
    598      * Returns true if the ok button is enabled.
    599      */
    600     private boolean isOkButtonEnabled() {
    601         Button okButton = getButton(IDialogConstants.OK_ID);
    602         return okButton.isEnabled();
    603     }
    604 
    605     /**
    606      * Executes the {@link Runnable} in the UI thread.
    607      * @param runnable the runnable to execute.
    608      */
    609     private void exec(Runnable runnable) {
    610         try {
    611             Display display = mDeviceTable.getDisplay();
    612             display.asyncExec(runnable);
    613         } catch (SWTException e) {
    614             // tree is disposed, we need to do something. lets remove ourselves from the listener.
    615             AndroidDebugBridge.removeDeviceChangeListener(this);
    616         }
    617     }
    618 
    619     private void handleDeviceSelection() {
    620         int count = mDeviceTable.getSelectionCount();
    621         if (count != 1) {
    622             handleSelection(null);
    623         } else {
    624             int index = mDeviceTable.getSelectionIndex();
    625             Object data = mViewer.getElementAt(index);
    626             if (data instanceof IDevice) {
    627                 handleSelection((IDevice)data);
    628             } else {
    629                 handleSelection(null);
    630             }
    631         }
    632     }
    633 
    634     private void handleSelection(IDevice device) {
    635         mResponse.setDeviceToUse(device);
    636         enableOkButton();
    637     }
    638 
    639     /**
    640      * Look for a default device to select. This is done by looking for the running
    641      * clients on each device and finding one similar to the one being launched.
    642      * <p/>
    643      * This is done every time the device list changed unless there is a already selection.
    644      */
    645     private void updateDefaultSelection() {
    646         if (mDeviceTable.getSelectionCount() == 0) {
    647             AndroidDebugBridge bridge = AndroidDebugBridge.getBridge();
    648 
    649             IDevice[] devices = bridge.getDevices();
    650 
    651             for (IDevice device : devices) {
    652                 Client[] clients = device.getClients();
    653 
    654                 for (Client client : clients) {
    655 
    656                     if (mPackageName.equals(client.getClientData().getClientDescription())) {
    657                         // found a match! Select it.
    658                         mViewer.setSelection(new StructuredSelection(device));
    659                         handleSelection(device);
    660 
    661                         // and we're done.
    662                         return;
    663                     }
    664                 }
    665             }
    666         }
    667 
    668         handleDeviceSelection();
    669     }
    670 
    671     private final class NonRunningAvdFilter implements IAvdFilter {
    672 
    673         private IDevice[] mDevices;
    674 
    675         public void prepare() {
    676             mDevices = AndroidDebugBridge.getBridge().getDevices();
    677         }
    678 
    679         public boolean accept(AvdInfo avd) {
    680             if (mDevices != null) {
    681                 for (IDevice d : mDevices) {
    682                     if (mProjectTarget.canRunOn(avd.getTarget()) == false ||
    683                             avd.getName().equals(d.getAvdName())) {
    684                         return false;
    685                     }
    686                 }
    687             }
    688 
    689             return true;
    690         }
    691 
    692         public void cleanup() {
    693             mDevices = null;
    694         }
    695     }
    696 
    697     /**
    698      * Refills the AVD list keeping the current selection.
    699      */
    700     private void refillAvdList(boolean reloadAvds) {
    701         // save the current selection
    702         AvdInfo selected = mPreferredAvdSelector.getSelected();
    703 
    704         // disable selection change.
    705         mDisableAvdSelectionChange = true;
    706 
    707         // refresh the list
    708         mPreferredAvdSelector.refresh(false);
    709 
    710         // attempt to reselect the proper avd if needed
    711         if (selected != null) {
    712             if (mPreferredAvdSelector.setSelection(selected) == false) {
    713                 // looks like the selection is lost. this can happen if an emulator
    714                 // running the AVD that was selected was launched from outside of Eclipse).
    715                 mResponse.setAvdToLaunch(null);
    716                 enableOkButton();
    717             }
    718         }
    719 
    720         // enable the selection change
    721         mDisableAvdSelectionChange = false;
    722     }
    723 }
    724 
    725