diff options
author | Siva Velusamy <vsiva@google.com> | 2012-07-26 15:41:15 -0700 |
---|---|---|
committer | Siva Velusamy <vsiva@google.com> | 2012-07-30 11:55:37 -0700 |
commit | 3685081c34cb5d240e38e714d6a0004cf4381928 (patch) | |
tree | d5041ef8d7a9454d128693d5afbde1a1fd584180 /eclipse | |
parent | 6a2d4d7796030c038ed0a59f1a68ae4d2108209f (diff) | |
download | sdk-3685081c34cb5d240e38e714d6a0004cf4381928.zip sdk-3685081c34cb5d240e38e714d6a0004cf4381928.tar.gz sdk-3685081c34cb5d240e38e714d6a0004cf4381928.tar.bz2 |
Use minSdk for device/avd compatibility checks
When checking whether a device can run a certain project,
the only valid conditionals are:
- If the device API level is less than the minApiLevel,
then the device cannot run the app.
- If the app is built against a standard SDK, then the above
check is sufficient.
- If the app is built against an add-on, then we cannot
determine for sure if a device can run the app.
An AVD might provide some additional info that can be
used to determine if the app cannot be run on a particular
AVD.
This CL fixes a bug where platforms with API level greater
than the build target API level were being filtered out from
the DeviceChooserDialog.
It also fixes another bug where running devices that are
clearly not capable of running an app were being displayed
in the DeviceChooserDialog, albeit with a red check mark
indicating that they cannot run the app. Selecting that
device for deployment would error out in the next step.
This CL filters out such devices.
Fixes http://code.google.com/p/android/issues/detail?id=35367
Change-Id: Iba31a45572dabe3895c4e51707ed515d407caae0
Diffstat (limited to 'eclipse')
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; |