• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.Client;
21 import com.android.ddmlib.IDevice;
22 import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener;
23 import com.android.ddmlib.IDevice.DeviceState;
24 import com.android.ddmuilib.IImageLoader;
25 import com.android.ddmuilib.ImageHelper;
26 import com.android.ddmuilib.TableHelper;
27 import com.android.ide.eclipse.adt.AdtPlugin;
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.AvdManager.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 class ContentProvider implements IStructuredContentProvider {
getElements(Object inputElement)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 
dispose()102         public void dispose() {
103             // pass
104         }
105 
inputChanged(Viewer viewer, Object oldInput, Object newInput)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 
getColumnImage(Object element, int columnIndex)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.isCompatibleBaseFor(info.getTarget()) ?
150                                     mMatchImage : mNoMatchImage;
151                         }
152                 }
153             }
154 
155             return null;
156         }
157 
getColumnText(Object element, int columnIndex)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 
addListener(ILabelProviderListener listener)200         public void addListener(ILabelProviderListener listener) {
201             // pass
202         }
203 
dispose()204         public void dispose() {
205             // pass
206         }
207 
isLabelProperty(Object element, String property)208         public boolean isLabelProperty(Object element, String property) {
209             // pass
210             return false;
211         }
212 
removeListener(ILabelProviderListener listener)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 
setDeviceToUse(IDevice d)222         public void setDeviceToUse(IDevice d) {
223             mDeviceToUse = d;
224             mAvdToLaunch = null;
225         }
226 
setAvdToLaunch(AvdInfo avd)227         public void setAvdToLaunch(AvdInfo avd) {
228             mAvdToLaunch = avd;
229             mDeviceToUse = null;
230         }
231 
getDeviceToUse()232         public IDevice getDeviceToUse() {
233             return mDeviceToUse;
234         }
235 
getAvdToLaunch()236         public AvdInfo getAvdToLaunch() {
237             return mAvdToLaunch;
238         }
239     }
240 
DeviceChooserDialog(Shell parent, DeviceChooserResponse response, String packageName, IAndroidTarget projectTarget)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 
cleanup()253     private void cleanup() {
254         // done listening.
255         AndroidDebugBridge.removeDeviceChangeListener(this);
256 
257         mEmulatorImage.dispose();
258         mDeviceImage.dispose();
259         mMatchImage.dispose();
260         mNoMatchImage.dispose();
261         mWarningImage.dispose();
262     }
263 
264     @Override
okPressed()265     protected void okPressed() {
266         cleanup();
267         super.okPressed();
268     }
269 
270     @Override
cancelPressed()271     protected void cancelPressed() {
272         cleanup();
273         super.cancelPressed();
274     }
275 
276     @Override
createContents(Composite parent)277     protected Control createContents(Composite parent) {
278         Control content = super.createContents(parent);
279 
280         // this must be called after createContents() has happened so that the
281         // ok button has been created (it's created after the call to createDialogArea)
282         updateDefaultSelection();
283 
284         return content;
285     }
286 
287 
288     @Override
createDialogArea(Composite parent)289     protected Control createDialogArea(Composite parent) {
290         // set dialog title
291         getShell().setText("Android Device Chooser");
292 
293         Composite top = new Composite(parent, SWT.NONE);
294         top.setLayout(new GridLayout(1, true));
295 
296         Label label = new Label(top, SWT.NONE);
297         label.setText(String.format("Select a device compatible with target %s.",
298                 mProjectTarget.getFullName()));
299 
300         mDeviceRadioButton = new Button(top, SWT.RADIO);
301         mDeviceRadioButton.setText("Choose a running Android device");
302         mDeviceRadioButton.addSelectionListener(new SelectionAdapter() {
303             @Override
304             public void widgetSelected(SelectionEvent e) {
305                 boolean deviceMode = mDeviceRadioButton.getSelection();
306 
307                 mDeviceTable.setEnabled(deviceMode);
308                 mPreferredAvdSelector.setEnabled(!deviceMode);
309 
310                 if (deviceMode) {
311                     handleDeviceSelection();
312                 } else {
313                     mResponse.setAvdToLaunch(mPreferredAvdSelector.getSelected());
314                 }
315 
316                 enableOkButton();
317             }
318         });
319         mDeviceRadioButton.setSelection(true);
320 
321 
322         // offset the selector from the radio button
323         Composite offsetComp = new Composite(top, SWT.NONE);
324         offsetComp.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
325         GridLayout layout = new GridLayout(1, false);
326         layout.marginRight = layout.marginHeight = 0;
327         layout.marginLeft = 30;
328         offsetComp.setLayout(layout);
329 
330         mDeviceTable = new Table(offsetComp, SWT.SINGLE | SWT.FULL_SELECTION | SWT.BORDER);
331         GridData gd;
332         mDeviceTable.setLayoutData(gd = new GridData(GridData.FILL_BOTH));
333         gd.heightHint = 100;
334 
335         mDeviceTable.setHeaderVisible(true);
336         mDeviceTable.setLinesVisible(true);
337 
338         TableHelper.createTableColumn(mDeviceTable, "Serial Number",
339                 SWT.LEFT, "AAA+AAAAAAAAAAAAAAAAAAA", //$NON-NLS-1$
340                 null /* prefs name */, null /* prefs store */);
341 
342         TableHelper.createTableColumn(mDeviceTable, "AVD Name",
343                 SWT.LEFT, "AAAAAAAAAAAAAAAAAAA", //$NON-NLS-1$
344                 null /* prefs name */, null /* prefs store */);
345 
346         TableHelper.createTableColumn(mDeviceTable, "Target",
347                 SWT.LEFT, "AAA+Android 9.9.9", //$NON-NLS-1$
348                 null /* prefs name */, null /* prefs store */);
349 
350         TableHelper.createTableColumn(mDeviceTable, "Debug",
351                 SWT.LEFT, "Debug", //$NON-NLS-1$
352                 null /* prefs name */, null /* prefs store */);
353 
354         TableHelper.createTableColumn(mDeviceTable, "State",
355                 SWT.LEFT, "bootloader", //$NON-NLS-1$
356                 null /* prefs name */, null /* prefs store */);
357 
358         // create the viewer for it
359         mViewer = new TableViewer(mDeviceTable);
360         mViewer.setContentProvider(new ContentProvider());
361         mViewer.setLabelProvider(new LabelProvider());
362         mViewer.setInput(AndroidDebugBridge.getBridge());
363 
364         mDeviceTable.addSelectionListener(new SelectionAdapter() {
365             /**
366              * Handles single-click selection on the device selector.
367              * {@inheritDoc}
368              */
369             @Override
370             public void widgetSelected(SelectionEvent e) {
371                 handleDeviceSelection();
372             }
373 
374             /**
375              * Handles double-click selection on the device selector.
376              * Note that the single-click handler will probably already have been called.
377              * {@inheritDoc}
378              */
379             @Override
380             public void widgetDefaultSelected(SelectionEvent e) {
381                 handleDeviceSelection();
382                 if (isOkButtonEnabled()) {
383                     okPressed();
384                 }
385             }
386         });
387 
388         Button radio2 = new Button(top, SWT.RADIO);
389         radio2.setText("Launch a new Android Virtual Device");
390 
391         // offset the selector from the radio button
392         offsetComp = new Composite(top, SWT.NONE);
393         offsetComp.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
394         layout = new GridLayout(1, false);
395         layout.marginRight = layout.marginHeight = 0;
396         layout.marginLeft = 30;
397         offsetComp.setLayout(layout);
398 
399         mPreferredAvdSelector = new AvdSelector(offsetComp,
400                 mSdk.getSdkLocation(),
401                 mSdk.getAvdManager(),
402                 new NonRunningAvdFilter(),
403                 DisplayMode.SIMPLE_SELECTION);
404         mPreferredAvdSelector.setTableHeightHint(100);
405         mPreferredAvdSelector.setEnabled(false);
406         mPreferredAvdSelector.setSelectionListener(new SelectionAdapter() {
407             /**
408              * Handles single-click selection on the AVD selector.
409              * {@inheritDoc}
410              */
411             @Override
412             public void widgetSelected(SelectionEvent e) {
413                 if (mDisableAvdSelectionChange == false) {
414                     mResponse.setAvdToLaunch(mPreferredAvdSelector.getSelected());
415                     enableOkButton();
416                 }
417             }
418 
419             /**
420              * Handles double-click selection on the AVD selector.
421              *
422              * Note that the single-click handler will probably already have been called
423              * but the selected item can have changed in between.
424              *
425              * {@inheritDoc}
426              */
427             @Override
428             public void widgetDefaultSelected(SelectionEvent e) {
429                 widgetSelected(e);
430                 if (isOkButtonEnabled()) {
431                     okPressed();
432                 }
433             }
434         });
435 
436 
437         return top;
438     }
439 
loadImages()440     private void loadImages() {
441         IImageLoader ddmsLoader = DdmsPlugin.getImageLoader();
442         Display display = DdmsPlugin.getDisplay();
443         IImageLoader adtLoader = AdtPlugin.getImageLoader();
444 
445         if (mDeviceImage == null) {
446             mDeviceImage = ImageHelper.loadImage(ddmsLoader, display,
447                     "device.png", //$NON-NLS-1$
448                     ICON_WIDTH, ICON_WIDTH,
449                     display.getSystemColor(SWT.COLOR_RED));
450         }
451         if (mEmulatorImage == null) {
452             mEmulatorImage = ImageHelper.loadImage(ddmsLoader, display,
453                     "emulator.png", ICON_WIDTH, ICON_WIDTH, //$NON-NLS-1$
454                     display.getSystemColor(SWT.COLOR_BLUE));
455         }
456 
457         if (mMatchImage == null) {
458             mMatchImage = ImageHelper.loadImage(adtLoader, display,
459                     "match.png", //$NON-NLS-1$
460                     ICON_WIDTH, ICON_WIDTH,
461                     display.getSystemColor(SWT.COLOR_GREEN));
462         }
463 
464         if (mNoMatchImage == null) {
465             mNoMatchImage = ImageHelper.loadImage(adtLoader, display,
466                     "error.png", //$NON-NLS-1$
467                     ICON_WIDTH, ICON_WIDTH,
468                     display.getSystemColor(SWT.COLOR_RED));
469         }
470 
471         if (mWarningImage == null) {
472             mWarningImage = ImageHelper.loadImage(adtLoader, display,
473                     "warning.png", //$NON-NLS-1$
474                     ICON_WIDTH, ICON_WIDTH,
475                     display.getSystemColor(SWT.COLOR_YELLOW));
476         }
477 
478     }
479 
480     /**
481      * Returns a display string representing the state of the device.
482      * @param d the device
483      */
getStateString(IDevice d)484     private static String getStateString(IDevice d) {
485         DeviceState deviceState = d.getState();
486         if (deviceState == DeviceState.ONLINE) {
487             return "Online";
488         } else if (deviceState == DeviceState.OFFLINE) {
489             return "Offline";
490         } else if (deviceState == DeviceState.BOOTLOADER) {
491             return "Bootloader";
492         }
493 
494         return "??";
495     }
496 
497     /**
498      * Sent when the a device is connected to the {@link AndroidDebugBridge}.
499      * <p/>
500      * This is sent from a non UI thread.
501      * @param device the new device.
502      *
503      * @see IDeviceChangeListener#deviceConnected(IDevice)
504      */
deviceConnected(IDevice device)505     public void deviceConnected(IDevice device) {
506         final DeviceChooserDialog dialog = this;
507         exec(new Runnable() {
508             public void run() {
509                 if (mDeviceTable.isDisposed() == false) {
510                     // refresh all
511                     mViewer.refresh();
512 
513                     // update the selection
514                     updateDefaultSelection();
515 
516                     // update the display of AvdInfo (since it's filtered to only display
517                     // non running AVD.)
518                     refillAvdList(false /*reloadAvds*/);
519                 } else {
520                     // table is disposed, we need to do something.
521                     // lets remove ourselves from the listener.
522                     AndroidDebugBridge.removeDeviceChangeListener(dialog);
523                 }
524 
525             }
526         });
527     }
528 
529     /**
530      * Sent when the a device is connected to the {@link AndroidDebugBridge}.
531      * <p/>
532      * This is sent from a non UI thread.
533      * @param device the new device.
534      *
535      * @see IDeviceChangeListener#deviceDisconnected(IDevice)
536      */
deviceDisconnected(IDevice device)537     public void deviceDisconnected(IDevice device) {
538         deviceConnected(device);
539     }
540 
541     /**
542      * Sent when a device data changed, or when clients are started/terminated on the device.
543      * <p/>
544      * This is sent from a non UI thread.
545      * @param device the device that was updated.
546      * @param changeMask the mask indicating what changed.
547      *
548      * @see IDeviceChangeListener#deviceChanged(IDevice, int)
549      */
deviceChanged(final IDevice device, int changeMask)550     public void deviceChanged(final IDevice device, int changeMask) {
551         if ((changeMask & (IDevice.CHANGE_STATE | IDevice.CHANGE_BUILD_INFO)) != 0) {
552             final DeviceChooserDialog dialog = this;
553             exec(new Runnable() {
554                 public void run() {
555                     if (mDeviceTable.isDisposed() == false) {
556                         // refresh the device
557                         mViewer.refresh(device);
558 
559                         // update the defaultSelection.
560                         updateDefaultSelection();
561 
562                         // update the display of AvdInfo (since it's filtered to only display
563                         // non running AVD). This is done on deviceChanged because the avd name
564                         // of a (emulator) device may be updated as the emulator boots.
565 
566                         refillAvdList(false /*reloadAvds*/);
567 
568                         // if the changed device is the current selection,
569                         // we update the OK button based on its state.
570                         if (device == mResponse.getDeviceToUse()) {
571                             enableOkButton();
572                         }
573 
574                     } else {
575                         // table is disposed, we need to do something.
576                         // lets remove ourselves from the listener.
577                         AndroidDebugBridge.removeDeviceChangeListener(dialog);
578                     }
579                 }
580             });
581         }
582     }
583 
584     /**
585      * Returns whether the dialog is in "device" mode (true), or in "avd" mode (false).
586      */
isDeviceMode()587     private boolean isDeviceMode() {
588         return mDeviceRadioButton.getSelection();
589     }
590 
591     /**
592      * Enables or disables the OK button of the dialog based on various selections in the dialog.
593      */
enableOkButton()594     private void enableOkButton() {
595         Button okButton = getButton(IDialogConstants.OK_ID);
596 
597         if (isDeviceMode()) {
598             okButton.setEnabled(mResponse.getDeviceToUse() != null &&
599                     mResponse.getDeviceToUse().isOnline());
600         } else {
601             okButton.setEnabled(mResponse.getAvdToLaunch() != null);
602         }
603     }
604 
605     /**
606      * Returns true if the ok button is enabled.
607      */
isOkButtonEnabled()608     private boolean isOkButtonEnabled() {
609         Button okButton = getButton(IDialogConstants.OK_ID);
610         return okButton.isEnabled();
611     }
612 
613     /**
614      * Executes the {@link Runnable} in the UI thread.
615      * @param runnable the runnable to execute.
616      */
exec(Runnable runnable)617     private void exec(Runnable runnable) {
618         try {
619             Display display = mDeviceTable.getDisplay();
620             display.asyncExec(runnable);
621         } catch (SWTException e) {
622             // tree is disposed, we need to do something. lets remove ourselves from the listener.
623             AndroidDebugBridge.removeDeviceChangeListener(this);
624         }
625     }
626 
handleDeviceSelection()627     private void handleDeviceSelection() {
628         int count = mDeviceTable.getSelectionCount();
629         if (count != 1) {
630             handleSelection(null);
631         } else {
632             int index = mDeviceTable.getSelectionIndex();
633             Object data = mViewer.getElementAt(index);
634             if (data instanceof IDevice) {
635                 handleSelection((IDevice)data);
636             } else {
637                 handleSelection(null);
638             }
639         }
640     }
641 
handleSelection(IDevice device)642     private void handleSelection(IDevice device) {
643         mResponse.setDeviceToUse(device);
644         enableOkButton();
645     }
646 
647     /**
648      * Look for a default device to select. This is done by looking for the running
649      * clients on each device and finding one similar to the one being launched.
650      * <p/>
651      * This is done every time the device list changed unless there is a already selection.
652      */
updateDefaultSelection()653     private void updateDefaultSelection() {
654         if (mDeviceTable.getSelectionCount() == 0) {
655             AndroidDebugBridge bridge = AndroidDebugBridge.getBridge();
656 
657             IDevice[] devices = bridge.getDevices();
658 
659             for (IDevice device : devices) {
660                 Client[] clients = device.getClients();
661 
662                 for (Client client : clients) {
663 
664                     if (mPackageName.equals(client.getClientData().getClientDescription())) {
665                         // found a match! Select it.
666                         mViewer.setSelection(new StructuredSelection(device));
667                         handleSelection(device);
668 
669                         // and we're done.
670                         return;
671                     }
672                 }
673             }
674         }
675 
676         handleDeviceSelection();
677     }
678 
679     private final class NonRunningAvdFilter implements IAvdFilter {
680 
681         private IDevice[] mDevices;
682 
prepare()683         public void prepare() {
684             mDevices = AndroidDebugBridge.getBridge().getDevices();
685         }
686 
accept(AvdInfo avd)687         public boolean accept(AvdInfo avd) {
688             if (mDevices != null) {
689                 for (IDevice d : mDevices) {
690                     if (mProjectTarget.isCompatibleBaseFor(avd.getTarget()) == false ||
691                             avd.getName().equals(d.getAvdName())) {
692                         return false;
693                     }
694                 }
695             }
696 
697             return true;
698         }
699 
cleanup()700         public void cleanup() {
701             mDevices = null;
702         }
703     }
704 
705     /**
706      * Refills the AVD list keeping the current selection.
707      */
refillAvdList(boolean reloadAvds)708     private void refillAvdList(boolean reloadAvds) {
709         // save the current selection
710         AvdInfo selected = mPreferredAvdSelector.getSelected();
711 
712         // disable selection change.
713         mDisableAvdSelectionChange = true;
714 
715         // refresh the list
716         mPreferredAvdSelector.refresh(false);
717 
718         // attempt to reselect the proper avd if needed
719         if (selected != null) {
720             if (mPreferredAvdSelector.setSelection(selected) == false) {
721                 // looks like the selection is lost. this can happen if an emulator
722                 // running the AVD that was selected was launched from outside of Eclipse).
723                 mResponse.setAvdToLaunch(null);
724                 enableOkButton();
725             }
726         }
727 
728         // enable the selection change
729         mDisableAvdSelectionChange = false;
730     }
731 }
732 
733