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