• 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.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.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.canRunOn(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 
258     @Override
okPressed()259     protected void okPressed() {
260         cleanup();
261         super.okPressed();
262     }
263 
264     @Override
cancelPressed()265     protected void cancelPressed() {
266         cleanup();
267         super.cancelPressed();
268     }
269 
270     @Override
createContents(Composite parent)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
createDialogArea(Composite parent)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 
loadImages()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             mNoMatchImage = 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      */
getStateString(IDevice d)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      */
deviceConnected(IDevice device)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      */
deviceDisconnected(IDevice device)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      */
deviceChanged(final IDevice device, int changeMask)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      */
isDeviceMode()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      */
enableOkButton()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      */
isOkButtonEnabled()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      */
exec(Runnable runnable)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 
handleDeviceSelection()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 
handleSelection(IDevice device)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      */
updateDefaultSelection()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 
prepare()675         public void prepare() {
676             mDevices = AndroidDebugBridge.getBridge().getDevices();
677         }
678 
accept(AvdInfo avd)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 
cleanup()692         public void cleanup() {
693             mDevices = null;
694         }
695     }
696 
697     /**
698      * Refills the AVD list keeping the current selection.
699      */
refillAvdList(boolean reloadAvds)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