diff options
3 files changed, 107 insertions, 55 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/AndroidLaunchController.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/AndroidLaunchController.java index 1f004f5..b8caadb 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/AndroidLaunchController.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/AndroidLaunchController.java @@ -31,6 +31,7 @@ import com.android.ddmlib.Log; import com.android.ddmlib.TimeoutException; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.internal.actions.AvdManagerAction; +import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo; import com.android.ide.eclipse.adt.internal.launch.AndroidLaunchConfiguration.TargetMode; import com.android.ide.eclipse.adt.internal.launch.DelayedLaunchInfo.InstallRetryMode; import com.android.ide.eclipse.adt.internal.launch.DeviceChooserDialog.DeviceChooserResponse; @@ -324,9 +325,15 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener config.mTargetMode = TargetMode.MANUAL; } - // get the project target + // get the sdk against which the project is built IAndroidTarget projectTarget = currentSdk.getTarget(project); + // get the min required android version + ManifestInfo mi = ManifestInfo.get(project); + final int minApiLevel = mi.getMinSdkVersion(); + final String minApiCodeName = mi.getMinSdkCodeName(); + final AndroidVersion minApiVersion = new AndroidVersion(minApiLevel, minApiCodeName); + // FIXME: check errors on missing sdk, AVD manager, or project target. // device chooser response object. @@ -370,17 +377,22 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener AvdInfo preferredAvd = null; if (config.mAvdName != null) { preferredAvd = avdManager.getAvd(config.mAvdName, true /*validAvdOnly*/); - if (projectTarget.canRunOn(preferredAvd.getTarget()) == false) { + IAndroidTarget preferredAvdTarget = preferredAvd.getTarget(); + if (preferredAvdTarget != null + && !preferredAvdTarget.getVersion().canRun(minApiVersion)) { preferredAvd = null; AdtPlugin.printErrorToConsole(project, String.format( - "Preferred AVD '%1$s' is not compatible with the project target '%2$s'. Looking for a compatible AVD...", - config.mAvdName, projectTarget.getName())); + "Preferred AVD '%1$s' (API Level: %2$d) cannot run application with minApi %3$s. Looking for a compatible AVD...", + config.mAvdName, + preferredAvdTarget.getVersion().getApiLevel(), + minApiVersion)); } } if (preferredAvd != null) { - // look for a matching device + // We have a preferred avd that can actually run the application. + // Now see if the AVD is running, and if so use it, otherwise launch it. for (IDevice d : devices) { String deviceAvd = d.getAvdName(); @@ -416,38 +428,31 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener // a device which target is the same as the project's target) and use it as the // new default. - int reqApiLevel = 0; - try { - reqApiLevel = Integer.parseInt(requiredApiVersionNumber); - - if (reqApiLevel > 0 && reqApiLevel < projectTarget.getVersion().getApiLevel()) { - int maxDist = projectTarget.getVersion().getApiLevel() - reqApiLevel; - IAndroidTarget candidate = null; - - for (IAndroidTarget target : currentSdk.getTargets()) { - if (target.canRunOn(projectTarget)) { - int currDist = target.getVersion().getApiLevel() - reqApiLevel; - if (currDist >= 0 && currDist < maxDist) { - maxDist = currDist; - candidate = target; - if (maxDist == 0) { - // Found a perfect match - break; - } + if (minApiCodeName != null && minApiLevel < projectTarget.getVersion().getApiLevel()) { + int maxDist = projectTarget.getVersion().getApiLevel() - minApiLevel; + IAndroidTarget candidate = null; + + for (IAndroidTarget target : currentSdk.getTargets()) { + if (target.canRunOn(projectTarget)) { + int currDist = target.getVersion().getApiLevel() - minApiLevel; + if (currDist >= 0 && currDist < maxDist) { + maxDist = currDist; + candidate = target; + if (maxDist == 0) { + // Found a perfect match + break; } } } + } - if (candidate != null) { - // We found a better SDK target candidate, that is closer to the - // API level from minSdkVersion than the one currently used by the - // project. Below (in the for...devices loop) we'll try to find - // a device/AVD for it. - projectTarget = candidate; - } + if (candidate != null) { + // We found a better SDK target candidate, that is closer to the + // API level from minSdkVersion than the one currently used by the + // project. Below (in the for...devices loop) we'll try to find + // a device/AVD for it. + projectTarget = candidate; } - } catch (NumberFormatException e) { - // pass } HashMap<IDevice, AvdInfo> compatibleRunningAvds = new HashMap<IDevice, AvdInfo>(); @@ -578,7 +583,7 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener boolean includeDevices = config.mTargetMode != TargetMode.ALL_EMULATORS; boolean includeAvds = config.mTargetMode != TargetMode.ALL_DEVICES; Collection<IDevice> compatibleDevices = findCompatibleDevices(devices, - requiredApiVersionNumber, includeDevices, includeAvds); + minApiVersion, includeDevices, includeAvds); if (compatibleDevices.size() == 0) { AdtPlugin.printErrorToConsole(project, "No active compatible AVD's or devices found. " @@ -601,7 +606,8 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener // or the AVD to launch. DeviceChooserDialog dialog = new DeviceChooserDialog( AdtPlugin.getDisplay().getActiveShell(), - response, launchInfo.getPackageName(), desiredProjectTarget); + response, launchInfo.getPackageName(), + desiredProjectTarget, minApiVersion); if (dialog.open() == Dialog.OK) { DeviceChoiceCache.put(launch.getLaunchConfiguration().getName(), response); continueLaunch.set(true); @@ -634,22 +640,14 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener /** * Returns devices that can run a app of provided API level. * @param devices list of devices to filter from - * @param requiredApiVersionNumber minimum required API level that should be supported + * @param requiredVersion minimum required API that should be supported * @param includeDevices include physical devices in the filtered list * @param includeAvds include emulators in the filtered list * @return set of compatible devices, may be an empty set */ private Collection<IDevice> findCompatibleDevices(IDevice[] devices, - String requiredApiVersionNumber, boolean includeDevices, boolean includeAvds) { + AndroidVersion requiredVersion, boolean includeDevices, boolean includeAvds) { Set<IDevice> compatibleDevices = new HashSet<IDevice>(devices.length); - int minApi; - try { - minApi = Integer.parseInt(requiredApiVersionNumber); - } catch (NumberFormatException e) { - minApi = 1; - } - AndroidVersion requiredVersion = new AndroidVersion(minApi, null); - AvdManager avdManager = Sdk.getCurrent().getAvdManager(); for (IDevice d: devices) { boolean isEmulator = d.isEmulator(); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/DeviceChooserDialog.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/DeviceChooserDialog.java index 781deaf..5638d51 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/DeviceChooserDialog.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/DeviceChooserDialog.java @@ -57,6 +57,9 @@ import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Table; +import java.util.ArrayList; +import java.util.List; + /** * A dialog that lets the user choose a device to deploy an application. * The user can either choose an exiting running device (including running emulators) @@ -80,6 +83,7 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener private final DeviceChooserResponse mResponse; private final String mPackageName; private final IAndroidTarget mProjectTarget; + private final AndroidVersion mMinApiVersion; private final Sdk mSdk; private Button mDeviceRadioButton; @@ -92,16 +96,32 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener * Basic Content Provider for a table full of {@link IDevice} objects. The input is * a {@link AndroidDebugBridge}. */ - private static class ContentProvider implements IStructuredContentProvider { + private class ContentProvider implements IStructuredContentProvider { @Override public Object[] getElements(Object inputElement) { if (inputElement instanceof AndroidDebugBridge) { - return ((AndroidDebugBridge)inputElement).getDevices(); + return findCompatibleDevices(((AndroidDebugBridge)inputElement).getDevices()); } return new Object[0]; } + private Object[] findCompatibleDevices(IDevice[] devices) { + if (devices == null) { + return null; + } + + List<IDevice> compatibleDevices = new ArrayList<IDevice>(devices.length); + for (IDevice device : devices) { + AndroidVersion deviceVersion = Sdk.getDeviceVersion(device); + if (deviceVersion == null || deviceVersion.canRun(mMinApiVersion)) { + compatibleDevices.add(device); + } + } + + return compatibleDevices.toArray(); + } + @Override public void dispose() { // pass @@ -113,7 +133,6 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener } } - /** * A Label Provider for the {@link TableViewer} in {@link DeviceChooserDialog}. * It provides labels and images for {@link IDevice} objects. @@ -136,7 +155,7 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener if (deviceVersion == null) { return mWarningImage; } else { - if (deviceVersion.canRun(mProjectTarget.getVersion()) == false) { + if (!deviceVersion.canRun(mMinApiVersion)) { return mNoMatchImage; } @@ -152,6 +171,17 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener if (info == null) { return mWarningImage; } + IAndroidTarget avdTarget = info.getTarget(); + if (avdTarget == null) { + return mWarningImage; + } + + // for platform targets, we only need to check the min api level + if (mProjectTarget.isPlatform() + && avdTarget.getVersion().canRun(mMinApiVersion)) + return mMatchImage; + + // for add on targets, check if required libraries are available return mProjectTarget.canRunOn(info.getTarget()) ? mMatchImage : mNoMatchImage; } @@ -259,12 +289,13 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener } public DeviceChooserDialog(Shell parent, DeviceChooserResponse response, String packageName, - IAndroidTarget projectTarget) { + IAndroidTarget projectTarget, AndroidVersion minApiVersion) { super(parent); mResponse = response; mPackageName = packageName; mProjectTarget = projectTarget; + mMinApiVersion = minApiVersion; mSdk = Sdk.getCurrent(); AndroidDebugBridge.addDeviceChangeListener(this); @@ -340,9 +371,16 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener Composite top = new Composite(parent, SWT.NONE); top.setLayout(new GridLayout(1, true)); + String msg; + if (mProjectTarget.isPlatform()) { + msg = String.format("Select a device with min API level %s.", + mMinApiVersion.getApiString()); + } else { + msg = String.format("Select a device compatible with target %s.", + mProjectTarget.getFullName()); + } Label label = new Label(top, SWT.NONE); - label.setText(String.format("Select a device compatible with target %s.", - mProjectTarget.getFullName())); + label.setText(msg); mDeviceRadioButton = new Button(top, SWT.RADIO); mDeviceRadioButton.setText("Choose a running Android device"); @@ -736,12 +774,23 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener @Override public boolean accept(AvdInfo avd) { + IAndroidTarget avdTarget = avd.getTarget(); + if (mDevices != null) { for (IDevice d : mDevices) { - if (mProjectTarget.canRunOn(avd.getTarget()) == false || - avd.getName().equals(d.getAvdName())) { + if (avd.getName().equals(d.getAvdName())) { return false; } + + if (avdTarget == null) { + return true; + } + + if (mProjectTarget.isPlatform()) { + return avdTarget.getVersion().canRun(mMinApiVersion); + } + + return mProjectTarget.canRunOn(avd.getTarget()); } } diff --git a/eclipse/plugins/com.android.ide.eclipse.ndk/src/com/android/ide/eclipse/ndk/internal/launch/NdkGdbLaunchDelegate.java b/eclipse/plugins/com.android.ide.eclipse.ndk/src/com/android/ide/eclipse/ndk/internal/launch/NdkGdbLaunchDelegate.java index 1c463ab..57d96d7 100644 --- a/eclipse/plugins/com.android.ide.eclipse.ndk/src/com/android/ide/eclipse/ndk/internal/launch/NdkGdbLaunchDelegate.java +++ b/eclipse/plugins/com.android.ide.eclipse.ndk/src/com/android/ide/eclipse/ndk/internal/launch/NdkGdbLaunchDelegate.java @@ -17,16 +17,17 @@ package com.android.ide.eclipse.ndk.internal.launch; import com.android.ddmlib.AdbCommandRejectedException; +import com.android.ddmlib.AndroidDebugBridge; import com.android.ddmlib.Client; import com.android.ddmlib.IDevice; import com.android.ddmlib.IDevice.DeviceUnixSocketNamespace; -import com.android.ddmlib.AndroidDebugBridge; import com.android.ddmlib.IShellOutputReceiver; import com.android.ddmlib.InstallException; import com.android.ddmlib.ShellCommandUnresponsiveException; import com.android.ddmlib.SyncException; import com.android.ddmlib.TimeoutException; import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo; import com.android.ide.eclipse.adt.internal.launch.DeviceChoiceCache; import com.android.ide.eclipse.adt.internal.launch.DeviceChooserDialog; import com.android.ide.eclipse.adt.internal.launch.DeviceChooserDialog.DeviceChooserResponse; @@ -119,6 +120,10 @@ public class NdkGdbLaunchDelegate extends GdbLaunchDelegate { } final ManifestData manifestData = AndroidManifestHelper.parseForData(project); + final ManifestInfo manifestInfo = ManifestInfo.get(project); + final AndroidVersion minSdkVersion = new AndroidVersion( + manifestInfo.getMinSdkVersion(), + manifestInfo.getMinSdkCodeName()); // Get the activity name to launch String activityName = getActivityToLaunch( @@ -159,7 +164,7 @@ public class NdkGdbLaunchDelegate extends GdbLaunchDelegate { AdtPlugin.getDisplay().getActiveShell(), response, manifestData.getPackage(), - projectTarget); + projectTarget, minSdkVersion); if (dialog.open() == Dialog.OK) { DeviceChoiceCache.put(configName, response); continueLaunch[0] = true; |