Add support for preview versions of platforms.

ro.build.version.codename is a new property indicating whether a platform
is in its release form (value = REL) or in development (value = dev branch
name such as Donut). When the codename indicates a development/preview version
then the API level must be ignored and this codename is used as a unique
identifier of the platform.

IAndroidTarget has been changed to return an instance of a new class
AndroidVersion instead of the api level directly. This class helps deals with
the logic of comparing version from targets or devices.

This change impacts all of the sdk manager to deal with targets identified by
codename instead of api level. This in turn impacts everything that relies
on the sdkmanager: ADT (build, launch, project creation), the AVD manager,
the SDK updater.
This commit is contained in:
Xavier Ducrohet
2009-07-20 14:43:50 -07:00
parent 89f0e50a4c
commit f2869cf9a9
28 changed files with 826 additions and 530 deletions

View File

@@ -130,9 +130,9 @@ public final class SetupTask extends ImportTask {
System.out.println("Project Target: " + androidTarget.getName()); System.out.println("Project Target: " + androidTarget.getName());
if (androidTarget.isPlatform() == false) { if (androidTarget.isPlatform() == false) {
System.out.println("Vendor: " + androidTarget.getVendor()); System.out.println("Vendor: " + androidTarget.getVendor());
System.out.println("Platform Version: " + androidTarget.getApiVersionName()); System.out.println("Platform Version: " + androidTarget.getVersionName());
} }
System.out.println("API level: " + androidTarget.getApiVersionNumber()); System.out.println("API level: " + androidTarget.getVersion().getApiString());
// sets up the properties to find android.jar/framework.aidl/target tools // sets up the properties to find android.jar/framework.aidl/target tools
String androidJar = androidTarget.getPath(IAndroidTarget.ANDROID_JAR); String androidJar = androidTarget.getPath(IAndroidTarget.ANDROID_JAR);

View File

@@ -28,8 +28,11 @@ import java.util.Map;
public interface IDevice { public interface IDevice {
public final static String PROP_BUILD_VERSION = "ro.build.version.release"; public final static String PROP_BUILD_VERSION = "ro.build.version.release";
public final static String PROP_BUILD_VERSION_NUMBER = "ro.build.version.sdk"; public final static String PROP_BUILD_API_LEVEL = "ro.build.version.sdk";
public final static String PROP_BUILD_CODENAME = "ro.build.version.codename";
public final static String PROP_DEBUGGABLE = "ro.debuggable"; public final static String PROP_DEBUGGABLE = "ro.debuggable";
/** Serial number of the first connected emulator. */ /** Serial number of the first connected emulator. */
public final static String FIRST_EMULATOR_SN = "emulator-5554"; //$NON-NLS-1$ public final static String FIRST_EMULATOR_SN = "emulator-5554"; //$NON-NLS-1$
/** Device change bit mask: {@link DeviceState} change. */ /** Device change bit mask: {@link DeviceState} change. */
@@ -39,6 +42,9 @@ public interface IDevice {
/** Device change bit mask: build info change. */ /** Device change bit mask: build info change. */
public static final int CHANGE_BUILD_INFO = 0x0004; public static final int CHANGE_BUILD_INFO = 0x0004;
/** @deprecated Use {@link #PROP_BUILD_API_LEVEL}. */
public final static String PROP_BUILD_VERSION_NUMBER = PROP_BUILD_API_LEVEL;
/** /**
* The state of a device. * The state of a device.
*/ */

View File

@@ -24,6 +24,7 @@ import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper;
import com.android.ide.eclipse.adt.internal.project.FixLaunchConfig; import com.android.ide.eclipse.adt.internal.project.FixLaunchConfig;
import com.android.ide.eclipse.adt.internal.project.XmlErrorHandler.BasicXmlErrorListener; import com.android.ide.eclipse.adt.internal.project.XmlErrorHandler.BasicXmlErrorListener;
import com.android.ide.eclipse.adt.internal.sdk.Sdk; import com.android.ide.eclipse.adt.internal.sdk.Sdk;
import com.android.sdklib.AndroidVersion;
import com.android.sdklib.IAndroidTarget; import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.SdkConstants; import com.android.sdklib.SdkConstants;
@@ -225,7 +226,7 @@ public class PreCompilerBuilder extends BaseBuilder {
PreCompilerDeltaVisitor dv = null; PreCompilerDeltaVisitor dv = null;
String javaPackage = null; String javaPackage = null;
int minSdkVersion = AndroidManifestParser.INVALID_MIN_SDK; String minSdkVersion = null;
if (kind == FULL_BUILD) { if (kind == FULL_BUILD) {
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
@@ -315,16 +316,62 @@ public class PreCompilerBuilder extends BaseBuilder {
minSdkVersion = parser.getApiLevelRequirement(); minSdkVersion = parser.getApiLevelRequirement();
} }
if (minSdkVersion != AndroidManifestParser.INVALID_MIN_SDK && if (minSdkVersion != null) {
minSdkVersion < projectTarget.getApiVersionNumber()) { int minSdkValue = -1;
// check it against the target api level try {
minSdkValue = Integer.parseInt(minSdkVersion);
} catch (NumberFormatException e) {
// it's ok, it means minSdkVersion contains a (hopefully) valid codename.
}
AndroidVersion projectVersion = projectTarget.getVersion();
if (minSdkValue != -1) {
String codename = projectVersion.getCodename();
if (codename != null) {
// integer minSdk when the target is a preview => fatal error
String msg = String.format(
"Platform %1$s is a preview and requires appication manifests to set %2$s to '%3$s'",
codename, AndroidManifestParser.ATTRIBUTE_MIN_SDK_VERSION,
codename);
AdtPlugin.printErrorToConsole(project, msg);
BaseProjectHelper.addMarker(manifest, AdtConstants.MARKER_ADT, msg,
IMarker.SEVERITY_ERROR);
stopBuild(msg);
} else if (minSdkValue < projectVersion.getApiLevel()) {
// integer minSdk is not high enough for the target => warning
String msg = String.format( String msg = String.format(
"Manifest min SDK version (%1$d) is lower than project target API level (%2$d)", "Manifest min SDK version (%1$d) is lower than project target API level (%2$d)",
minSdkVersion, projectTarget.getApiVersionNumber()); minSdkVersion, projectVersion.getApiLevel());
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg); AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg);
BaseProjectHelper.addMarker(manifest, AdtConstants.MARKER_ADT, msg, BaseProjectHelper.addMarker(manifest, AdtConstants.MARKER_ADT, msg,
IMarker.SEVERITY_WARNING); IMarker.SEVERITY_WARNING);
} }
} else {
// looks like the min sdk is a codename, check it matches the codename
// of the platform
String codename = projectVersion.getCodename();
if (codename == null) {
// platform is not a preview => fatal error
String msg = String.format(
"Manifest attribute '%1$s' is set to '%2$s'. Integer is expected.",
AndroidManifestParser.ATTRIBUTE_MIN_SDK_VERSION, codename);
AdtPlugin.printErrorToConsole(project, msg);
BaseProjectHelper.addMarker(manifest, AdtConstants.MARKER_ADT, msg,
IMarker.SEVERITY_ERROR);
stopBuild(msg);
} else if (codename.equals(minSdkVersion) == false) {
// platform and manifest codenames don't match => fatal error.
String msg = String.format(
"Value of manifest attribute '%1$s' does not match platform codename '%2$s'",
AndroidManifestParser.ATTRIBUTE_MIN_SDK_VERSION, codename);
AdtPlugin.printErrorToConsole(project, msg);
BaseProjectHelper.addMarker(manifest, AdtConstants.MARKER_ADT, msg,
IMarker.SEVERITY_ERROR);
stopBuild(msg);
}
}
}
if (javaPackage == null || javaPackage.length() == 0) { if (javaPackage == null || javaPackage.length() == 0) {
// looks like the AndroidManifest file isn't valid. // looks like the AndroidManifest file isn't valid.

View File

@@ -91,7 +91,7 @@ class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements
/** Application Package, gathered from the parsing of the manifest */ /** Application Package, gathered from the parsing of the manifest */
private String mJavaPackage = null; private String mJavaPackage = null;
/** minSDKVersion attribute value, gathered from the parsing of the manifest */ /** minSDKVersion attribute value, gathered from the parsing of the manifest */
private int mMinSdkVersion = AndroidManifestParser.INVALID_MIN_SDK; private String mMinSdkVersion = null;
// Internal usage fields. // Internal usage fields.
/** /**
@@ -162,16 +162,16 @@ class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements
/** /**
* Returns the minSDkVersion attribute from the manifest if it was checked/parsed. * Returns the minSDkVersion attribute from the manifest if it was checked/parsed.
* <p/> * <p/>
* This can return {@link AndroidManifestParser#INVALID_MIN_SDK} in two cases: * This can return null in two cases:
* <ul> * <ul>
* <li>The manifest was not part of the resource change delta, and the manifest was * <li>The manifest was not part of the resource change delta, and the manifest was
* not checked/parsed ({@link #getCheckedManifestXml()} returns <code>false</code>)</li> * not checked/parsed ({@link #getCheckedManifestXml()} returns <code>false</code>)</li>
* <li>The manifest was parsed ({@link #getCheckedManifestXml()} returns <code>true</code>), * <li>The manifest was parsed ({@link #getCheckedManifestXml()} returns <code>true</code>),
* but the package declaration is missing</li> * but the package declaration is missing</li>
* </ul> * </ul>
* @return the minSdkVersion or {@link AndroidManifestParser#INVALID_MIN_SDK}. * @return the minSdkVersion or null.
*/ */
public int getMinSdkVersion() { public String getMinSdkVersion() {
return mMinSdkVersion; return mMinSdkVersion;
} }

View File

@@ -35,9 +35,9 @@ import com.android.ide.eclipse.adt.internal.project.ProjectHelper;
import com.android.ide.eclipse.adt.internal.sdk.Sdk; import com.android.ide.eclipse.adt.internal.sdk.Sdk;
import com.android.ide.eclipse.adt.internal.wizards.actions.AvdManagerAction; import com.android.ide.eclipse.adt.internal.wizards.actions.AvdManagerAction;
import com.android.prefs.AndroidLocation.AndroidLocationException; import com.android.prefs.AndroidLocation.AndroidLocationException;
import com.android.sdklib.AndroidVersion;
import com.android.sdklib.IAndroidTarget; import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.NullSdkLog; import com.android.sdklib.NullSdkLog;
import com.android.sdklib.SdkManager;
import com.android.sdklib.internal.avd.AvdManager; import com.android.sdklib.internal.avd.AvdManager;
import com.android.sdklib.internal.avd.AvdManager.AvdInfo; import com.android.sdklib.internal.avd.AvdManager.AvdInfo;
@@ -274,16 +274,16 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
* @param packageName the Android package name of the app * @param packageName the Android package name of the app
* @param debugPackageName the Android package name to debug * @param debugPackageName the Android package name to debug
* @param debuggable the debuggable value of the app, or null if not set. * @param debuggable the debuggable value of the app, or null if not set.
* @param requiredApiVersionNumber the api version required by the app, or * @param requiredApiVersionNumber the api version required by the app, or null if none.
* {@link AndroidManifestParser#INVALID_MIN_SDK} if none.
* @param launchAction the action to perform after app sync * @param launchAction the action to perform after app sync
* @param config the launch configuration * @param config the launch configuration
* @param launch the launch object * @param launch the launch object
*/ */
public void launch(final IProject project, String mode, IFile apk, public void launch(final IProject project, String mode, IFile apk,
String packageName, String debugPackageName, Boolean debuggable, int requiredApiVersionNumber, String packageName, String debugPackageName, Boolean debuggable,
final IAndroidLaunchAction launchAction, final AndroidLaunchConfiguration config, String requiredApiVersionNumber, final IAndroidLaunchAction launchAction,
final AndroidLaunch launch, IProgressMonitor monitor) { final AndroidLaunchConfiguration config, final AndroidLaunch launch,
IProgressMonitor monitor) {
String message = String.format("Performing %1$s", launchAction.getLaunchDescription()); String message = String.format("Performing %1$s", launchAction.getLaunchDescription());
AdtPlugin.printToConsole(project, message); AdtPlugin.printToConsole(project, message);
@@ -398,17 +398,16 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
} else { } else {
if (projectTarget.isPlatform()) { // means this can run on any device as long if (projectTarget.isPlatform()) { // means this can run on any device as long
// as api level is high enough // as api level is high enough
String apiString = d.getProperty(SdkManager.PROP_VERSION_SDK); AndroidVersion deviceVersion = Sdk.getDeviceVersion(d);
try { if (deviceVersion.canRun(projectTarget.getVersion())) {
int apiNumber = Integer.parseInt(apiString);
if (apiNumber >= projectTarget.getApiVersionNumber()) {
// device is compatible with project // device is compatible with project
compatibleRunningAvds.put(d, null); compatibleRunningAvds.put(d, null);
continue; continue;
} }
} catch (NumberFormatException e) { } else {
// do nothing, we'll consider it a non compatible device below. // for non project platform, we can't be sure if a device can
} // run an application or not, since we don't query the device
// for the list of optional libraries that it supports.
} }
hasDevice = true; hasDevice = true;
} }
@@ -544,9 +543,12 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
AvdInfo defaultAvd = null; AvdInfo defaultAvd = null;
for (AvdInfo avd : avds) { for (AvdInfo avd : avds) {
if (projectTarget.isCompatibleBaseFor(avd.getTarget())) { if (projectTarget.isCompatibleBaseFor(avd.getTarget())) {
// at this point we can ignore the code name issue since
// IAndroidTarget.isCompatibleBaseFor() will already have filtered the non
// compatible AVDs.
if (defaultAvd == null || if (defaultAvd == null ||
avd.getTarget().getApiVersionNumber() < avd.getTarget().getVersion().getApiLevel() <
defaultAvd.getTarget().getApiVersionNumber()) { defaultAvd.getTarget().getVersion().getApiLevel()) {
defaultAvd = avd; defaultAvd = avd;
} }
} }
@@ -654,46 +656,66 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
if (device != null) { if (device != null) {
// check the app required API level versus the target device API level // check the app required API level versus the target device API level
String deviceApiVersionName = device.getProperty(IDevice.PROP_BUILD_VERSION); String deviceVersion = device.getProperty(IDevice.PROP_BUILD_VERSION);
String value = device.getProperty(IDevice.PROP_BUILD_VERSION_NUMBER); String deviceApiLevelString = device.getProperty(IDevice.PROP_BUILD_API_LEVEL);
int deviceApiVersionNumber = AndroidManifestParser.INVALID_MIN_SDK; String deviceCodeName = device.getProperty(IDevice.PROP_BUILD_CODENAME);
int deviceApiLevel = -1;
try { try {
deviceApiVersionNumber = Integer.parseInt(value); deviceApiLevel = Integer.parseInt(deviceApiLevelString);
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
// pass, we'll keep the deviceVersionNumber value at 0. // pass, we'll keep the apiLevel value at -1.
} }
if (launchInfo.getRequiredApiVersionNumber() == AndroidManifestParser.INVALID_MIN_SDK) { String requiredApiString = launchInfo.getRequiredApiVersionNumber();
// warn the API level requirement is not set. if (requiredApiString != null) {
AdtPlugin.printErrorToConsole(launchInfo.getProject(), int requiredApi = -1;
"WARNING: Application does not specify an API level requirement!"); try {
requiredApi = Integer.parseInt(requiredApiString);
} catch (NumberFormatException e) {
// pass, we'll keep requiredApi value at -1.
}
// and display the target device API level (if known) if (requiredApi == -1) {
if (deviceApiVersionName == null || // this means the manifest uses a codename for minSdkVersion
deviceApiVersionNumber == AndroidManifestParser.INVALID_MIN_SDK) { // check that the device is using the same codename
AdtPlugin.printErrorToConsole(launchInfo.getProject(), if (requiredApiString.equals(deviceCodeName) == false) {
"WARNING: Unknown device API version!");
} else {
AdtPlugin.printErrorToConsole(launchInfo.getProject(), String.format( AdtPlugin.printErrorToConsole(launchInfo.getProject(), String.format(
"Device API version is %1$d (Android %2$s)", deviceApiVersionNumber, "ERROR: Application requires a device running '%1$s'!",
deviceApiVersionName)); requiredApiString));
return false;
} }
} else { // app requires a specific API level } else {
if (deviceApiVersionName == null || // app requires a specific API level
deviceApiVersionNumber == AndroidManifestParser.INVALID_MIN_SDK) { if (deviceApiLevel == -1) {
AdtPlugin.printToConsole(launchInfo.getProject(), AdtPlugin.printToConsole(launchInfo.getProject(),
"WARNING: Unknown device API version!"); "WARNING: Unknown device API version!");
} else if (deviceApiVersionNumber < launchInfo.getRequiredApiVersionNumber()) { } else if (deviceApiLevel < requiredApi) {
String msg = String.format( String msg = String.format(
"ERROR: Application requires API version %1$d. Device API version is %2$d (Android %3$s).", "ERROR: Application requires API version %1$d. Device API version is %2$d (Android %3$s).",
launchInfo.getRequiredApiVersionNumber(), deviceApiVersionNumber, requiredApi, deviceApiLevel, deviceVersion);
deviceApiVersionName);
AdtPlugin.printErrorToConsole(launchInfo.getProject(), msg); AdtPlugin.printErrorToConsole(launchInfo.getProject(), msg);
// abort the launch // abort the launch
return false; return false;
} }
} }
} else {
// warn the application API level requirement is not set.
AdtPlugin.printErrorToConsole(launchInfo.getProject(),
"WARNING: Application does not specify an API level requirement!");
// and display the target device API level (if known)
if (deviceApiLevel == -1) {
AdtPlugin.printErrorToConsole(launchInfo.getProject(),
"WARNING: Unknown device API version!");
} else {
AdtPlugin.printErrorToConsole(launchInfo.getProject(), String.format(
"Device API version is %1$d (Android %2$s)", deviceApiLevel,
deviceVersion));
}
}
// now checks that the device/app can be debugged (if needed) // now checks that the device/app can be debugged (if needed)
if (device.isEmulator() == false && launchInfo.isDebugMode()) { if (device.isEmulator() == false && launchInfo.isDebugMode()) {

View File

@@ -17,7 +17,6 @@
package com.android.ide.eclipse.adt.internal.launch; package com.android.ide.eclipse.adt.internal.launch;
import com.android.ddmlib.IDevice; import com.android.ddmlib.IDevice;
import com.android.ide.eclipse.adt.internal.project.AndroidManifestParser;
import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProject;
@@ -54,9 +53,8 @@ public final class DelayedLaunchInfo {
/** debuggable attribute of the manifest file. */ /** debuggable attribute of the manifest file. */
private final Boolean mDebuggable; private final Boolean mDebuggable;
/** Required ApiVersionNumber by the app. {@link AndroidManifestParser#INVALID_MIN_SDK} means /** Required Api level by the app. null means no requirements */
* no requirements */ private final String mRequiredApiVersionNumber;
private final int mRequiredApiVersionNumber;
private InstallRetryMode mRetryMode = InstallRetryMode.NEVER; private InstallRetryMode mRetryMode = InstallRetryMode.NEVER;
@@ -87,14 +85,13 @@ public final class DelayedLaunchInfo {
* @param launchAction action to perform after app install * @param launchAction action to perform after app install
* @param pack IFile to the package (.apk) file * @param pack IFile to the package (.apk) file
* @param debuggable debuggable attribute of the app's manifest file. * @param debuggable debuggable attribute of the app's manifest file.
* @param requiredApiVersionNumber required SDK version by the app. * @param requiredApiVersionNumber required SDK version by the app. null means no requirements.
* {@link AndroidManifestParser#INVALID_MIN_SDK} means no requirements.
* @param launch the launch object * @param launch the launch object
* @param monitor progress monitor for launch * @param monitor progress monitor for launch
*/ */
public DelayedLaunchInfo(IProject project, String packageName, String debugPackageName, public DelayedLaunchInfo(IProject project, String packageName, String debugPackageName,
IAndroidLaunchAction launchAction, IFile pack, Boolean debuggable, IAndroidLaunchAction launchAction, IFile pack, Boolean debuggable,
int requiredApiVersionNumber, AndroidLaunch launch, IProgressMonitor monitor) { String requiredApiVersionNumber, AndroidLaunch launch, IProgressMonitor monitor) {
mProject = project; mProject = project;
mPackageName = packageName; mPackageName = packageName;
mDebugPackageName = debugPackageName; mDebugPackageName = debugPackageName;
@@ -160,9 +157,9 @@ public final class DelayedLaunchInfo {
} }
/** /**
* @return the required api version number for the Android app * @return the required api version number for the Android app.
*/ */
public int getRequiredApiVersionNumber() { public String getRequiredApiVersionNumber() {
return mRequiredApiVersionNumber; return mRequiredApiVersionNumber;
} }

View File

@@ -27,6 +27,7 @@ import com.android.ddmuilib.TableHelper;
import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.internal.sdk.Sdk; import com.android.ide.eclipse.adt.internal.sdk.Sdk;
import com.android.ide.eclipse.ddms.DdmsPlugin; import com.android.ide.eclipse.ddms.DdmsPlugin;
import com.android.sdklib.AndroidVersion;
import com.android.sdklib.IAndroidTarget; import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.internal.avd.AvdManager.AvdInfo; import com.android.sdklib.internal.avd.AvdManager.AvdInfo;
import com.android.sdkuilib.internal.widgets.AvdSelector; import com.android.sdkuilib.internal.widgets.AvdSelector;
@@ -131,26 +132,19 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener
case 2: case 2:
// check for compatibility. // check for compatibility.
if (device.isEmulator() == false) { // physical device if (device.isEmulator() == false) { // physical device
// get the api level of the device // get the version of the device
try { AndroidVersion deviceVersion = Sdk.getDeviceVersion(device);
String apiValue = device.getProperty( if (deviceVersion == null) {
IDevice.PROP_BUILD_VERSION_NUMBER); return mWarningImage;
if (apiValue != null) { } else {
int api = Integer.parseInt(apiValue); if (deviceVersion.canRun(mProjectTarget.getVersion()) == false) {
if (api >= mProjectTarget.getApiVersionNumber()) { return mNoMatchImage;
// if the project is compiling against an add-on, the optional }
// API may be missing from the device.
// if the project is compiling against an add-on,
// the optional API may be missing from the device.
return mProjectTarget.isPlatform() ? return mProjectTarget.isPlatform() ?
mMatchImage : mWarningImage; mMatchImage : mWarningImage;
} else {
return mNoMatchImage;
}
} else {
return mWarningImage;
}
} catch (NumberFormatException e) {
// lets consider the device non compatible
return mNoMatchImage;
} }
} else { } else {
// get the AvdInfo // get the AvdInfo

View File

@@ -51,7 +51,7 @@ public class AndroidManifestParser {
private final static String ATTRIBUTE_NAME = "name"; //$NON-NLS-1$ private final static String ATTRIBUTE_NAME = "name"; //$NON-NLS-1$
private final static String ATTRIBUTE_PROCESS = "process"; //$NON-NLS-$ private final static String ATTRIBUTE_PROCESS = "process"; //$NON-NLS-$
private final static String ATTRIBUTE_DEBUGGABLE = "debuggable"; //$NON-NLS-$ private final static String ATTRIBUTE_DEBUGGABLE = "debuggable"; //$NON-NLS-$
private final static String ATTRIBUTE_MIN_SDK_VERSION = "minSdkVersion"; //$NON-NLS-$ public final static String ATTRIBUTE_MIN_SDK_VERSION = "minSdkVersion"; //$NON-NLS-$
private final static String ATTRIBUTE_TARGET_PACKAGE = "targetPackage"; //$NON-NLS-1$ private final static String ATTRIBUTE_TARGET_PACKAGE = "targetPackage"; //$NON-NLS-1$
private final static String ATTRIBUTE_EXPORTED = "exported"; //$NON-NLS-1$ private final static String ATTRIBUTE_EXPORTED = "exported"; //$NON-NLS-1$
private final static String NODE_MANIFEST = "manifest"; //$NON-NLS-1$ private final static String NODE_MANIFEST = "manifest"; //$NON-NLS-1$
@@ -76,8 +76,6 @@ public class AndroidManifestParser {
private final static String ACTION_MAIN = "android.intent.action.MAIN"; //$NON-NLS-1$ private final static String ACTION_MAIN = "android.intent.action.MAIN"; //$NON-NLS-1$
private final static String CATEGORY_LAUNCHER = "android.intent.category.LAUNCHER"; //$NON-NLS-1$ private final static String CATEGORY_LAUNCHER = "android.intent.category.LAUNCHER"; //$NON-NLS-1$
public final static int INVALID_MIN_SDK = -1;
/** /**
* Instrumentation info obtained from manifest * Instrumentation info obtained from manifest
*/ */
@@ -179,9 +177,8 @@ public class AndroidManifestParser {
private Set<String> mProcesses = null; private Set<String> mProcesses = null;
/** debuggable attribute value. If null, the attribute is not present. */ /** debuggable attribute value. If null, the attribute is not present. */
private Boolean mDebuggable = null; private Boolean mDebuggable = null;
/** API level requirement. if {@link AndroidManifestParser#INVALID_MIN_SDK} /** API level requirement. if null the attribute was not present. */
* the attribute was not present. */ private String mApiLevelRequirement = null;
private int mApiLevelRequirement = INVALID_MIN_SDK;
/** List of all instrumentations declared by the manifest */ /** List of all instrumentations declared by the manifest */
private final ArrayList<Instrumentation> mInstrumentations = private final ArrayList<Instrumentation> mInstrumentations =
new ArrayList<Instrumentation>(); new ArrayList<Instrumentation>();
@@ -258,10 +255,9 @@ public class AndroidManifestParser {
} }
/** /**
* Returns the <code>minSdkVersion</code> attribute, or * Returns the <code>minSdkVersion</code> attribute, or null if it's not set.
* {@link AndroidManifestParser#INVALID_MIN_SDK} if it's not set.
*/ */
int getApiLevelRequirement() { String getApiLevelRequirement() {
return mApiLevelRequirement; return mApiLevelRequirement;
} }
@@ -331,16 +327,8 @@ public class AndroidManifestParser {
mValidLevel++; mValidLevel++;
} else if (NODE_USES_SDK.equals(localName)) { } else if (NODE_USES_SDK.equals(localName)) {
value = getAttributeValue(attributes, ATTRIBUTE_MIN_SDK_VERSION, mApiLevelRequirement = getAttributeValue(attributes,
true /* hasNamespace */); ATTRIBUTE_MIN_SDK_VERSION, true /* hasNamespace */);
if (value != null) {
try {
mApiLevelRequirement = Integer.parseInt(value);
} catch (NumberFormatException e) {
handleError(e, -1 /* lineNumber */);
}
}
} else if (NODE_INSTRUMENTATION.equals(localName)) { } else if (NODE_INSTRUMENTATION.equals(localName)) {
processInstrumentationNode(attributes); processInstrumentationNode(attributes);
} }
@@ -636,7 +624,7 @@ public class AndroidManifestParser {
private final Activity mLauncherActivity; private final Activity mLauncherActivity;
private final String[] mProcesses; private final String[] mProcesses;
private final Boolean mDebuggable; private final Boolean mDebuggable;
private final int mApiLevelRequirement; private final String mApiLevelRequirement;
private final Instrumentation[] mInstrumentations; private final Instrumentation[] mInstrumentations;
private final String[] mLibraries; private final String[] mLibraries;
@@ -904,10 +892,9 @@ public class AndroidManifestParser {
} }
/** /**
* Returns the <code>minSdkVersion</code> attribute, or {@link #INVALID_MIN_SDK} * Returns the <code>minSdkVersion</code> attribute, or null if it's not set.
* if it's not set.
*/ */
public int getApiLevelRequirement() { public String getApiLevelRequirement() {
return mApiLevelRequirement; return mApiLevelRequirement;
} }
@@ -939,13 +926,13 @@ public class AndroidManifestParser {
* @param launcherActivity the launcher activity parser from the manifest. * @param launcherActivity the launcher activity parser from the manifest.
* @param processes the list of custom processes declared in the manifest. * @param processes the list of custom processes declared in the manifest.
* @param debuggable the debuggable attribute, or null if not set. * @param debuggable the debuggable attribute, or null if not set.
* @param apiLevelRequirement the minSdkVersion attribute value or 0 if not set. * @param apiLevelRequirement the minSdkVersion attribute value or null if not set.
* @param instrumentations the list of instrumentations parsed from the manifest. * @param instrumentations the list of instrumentations parsed from the manifest.
* @param libraries the list of libraries in use parsed from the manifest. * @param libraries the list of libraries in use parsed from the manifest.
*/ */
private AndroidManifestParser(String javaPackage, Activity[] activities, private AndroidManifestParser(String javaPackage, Activity[] activities,
Activity launcherActivity, String[] processes, Boolean debuggable, Activity launcherActivity, String[] processes, Boolean debuggable,
int apiLevelRequirement, Instrumentation[] instrumentations, String[] libraries) { String apiLevelRequirement, Instrumentation[] instrumentations, String[] libraries) {
mJavaPackage = javaPackage; mJavaPackage = javaPackage;
mActivities = activities; mActivities = activities;
mLauncherActivity = launcherActivity; mLauncherActivity = launcherActivity;

View File

@@ -203,7 +203,7 @@ public final class AndroidTargetParser {
Map<String, Map<String, Integer>> enumValueMap = attrsXmlParser.getEnumFlagValues(); Map<String, Map<String, Integer>> enumValueMap = attrsXmlParser.getEnumFlagValues();
Map<String, DeclareStyleableInfo> xmlAppWidgetMap = null; Map<String, DeclareStyleableInfo> xmlAppWidgetMap = null;
if (mAndroidTarget.getApiVersionNumber() >= 3) { if (mAndroidTarget.getVersion().getApiLevel() >= 3) {
xmlAppWidgetMap = collectAppWidgetDefinitions(attrsXmlParser); xmlAppWidgetMap = collectAppWidgetDefinitions(attrsXmlParser);
} }

View File

@@ -16,12 +16,14 @@
package com.android.ide.eclipse.adt.internal.sdk; package com.android.ide.eclipse.adt.internal.sdk;
import com.android.ddmlib.IDevice;
import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.internal.project.AndroidClasspathContainerInitializer; import com.android.ide.eclipse.adt.internal.project.AndroidClasspathContainerInitializer;
import com.android.ide.eclipse.adt.internal.resources.manager.ResourceMonitor; import com.android.ide.eclipse.adt.internal.resources.manager.ResourceMonitor;
import com.android.ide.eclipse.adt.internal.resources.manager.ResourceMonitor.IProjectListener; import com.android.ide.eclipse.adt.internal.resources.manager.ResourceMonitor.IProjectListener;
import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData.LayoutBridge; import com.android.ide.eclipse.adt.internal.sdk.AndroidTargetData.LayoutBridge;
import com.android.prefs.AndroidLocation.AndroidLocationException; import com.android.prefs.AndroidLocation.AndroidLocationException;
import com.android.sdklib.AndroidVersion;
import com.android.sdklib.IAndroidTarget; import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.ISdkLog; import com.android.sdklib.ISdkLog;
import com.android.sdklib.SdkConstants; import com.android.sdklib.SdkConstants;
@@ -394,6 +396,21 @@ public class Sdk implements IProjectListener {
return mAvdManager; return mAvdManager;
} }
public static AndroidVersion getDeviceVersion(IDevice device) {
try {
Map<String, String> props = device.getProperties();
String apiLevel = props.get(IDevice.PROP_BUILD_API_LEVEL);
if (apiLevel == null) {
return null;
}
return new AndroidVersion(Integer.parseInt(apiLevel),
props.get((IDevice.PROP_BUILD_CODENAME)));
} catch (NumberFormatException e) {
return null;
}
}
private Sdk(SdkManager manager, AvdManager avdManager) { private Sdk(SdkManager manager, AvdManager avdManager) {
mManager = manager; mManager = manager;
mAvdManager = avdManager; mAvdManager = avdManager;

View File

@@ -840,26 +840,22 @@ public class NewProjectCreationPage extends WizardPage {
return; return;
} }
try { String minSdkVersion = mInfo.getMinSdkVersion();
int version = Integer.parseInt(mInfo.getMinSdkVersion());
// Before changing, compare with the currently selected one, if any. // Before changing, compare with the currently selected one, if any.
// There can be multiple targets with the same sdk api version, so don't change // There can be multiple targets with the same sdk api version, so don't change
// it if it's already at the right version. // it if it's already at the right version.
IAndroidTarget curr_target = mInfo.getSdkTarget(); IAndroidTarget curr_target = mInfo.getSdkTarget();
if (curr_target != null && curr_target.getApiVersionNumber() == version) { if (curr_target != null && curr_target.getVersion().equals(minSdkVersion)) {
return; return;
} }
for (IAndroidTarget target : mSdkTargetSelector.getTargets()) { for (IAndroidTarget target : mSdkTargetSelector.getTargets()) {
if (target.getApiVersionNumber() == version) { if (target.getVersion().equals(minSdkVersion)) {
mSdkTargetSelector.setSelection(target); mSdkTargetSelector.setSelection(target);
break; break;
} }
} }
} catch (NumberFormatException e) {
// ignore
}
} }
/** /**
@@ -873,7 +869,7 @@ public class NewProjectCreationPage extends WizardPage {
if (target != null) { if (target != null) {
mInternalMinSdkVersionUpdate = true; mInternalMinSdkVersionUpdate = true;
mMinSdkVersionField.setText(Integer.toString(target.getApiVersionNumber())); mMinSdkVersionField.setText(target.getVersion().getApiString());
mInternalMinSdkVersionUpdate = false; mInternalMinSdkVersionUpdate = false;
} }
} }
@@ -932,7 +928,7 @@ public class NewProjectCreationPage extends WizardPage {
String packageName = null; String packageName = null;
Activity activity = null; Activity activity = null;
String activityName = null; String activityName = null;
int minSdkVersion = AndroidManifestParser.INVALID_MIN_SDK; String minSdkVersion = null;
try { try {
packageName = manifestData.getPackage(); packageName = manifestData.getPackage();
minSdkVersion = manifestData.getApiLevelRequirement(); minSdkVersion = manifestData.getApiLevelRequirement();
@@ -1033,18 +1029,14 @@ public class NewProjectCreationPage extends WizardPage {
} }
} }
if (!foundTarget && minSdkVersion != AndroidManifestParser.INVALID_MIN_SDK) { if (!foundTarget && minSdkVersion != null) {
try {
for (IAndroidTarget target : mSdkTargetSelector.getTargets()) { for (IAndroidTarget target : mSdkTargetSelector.getTargets()) {
if (target.getApiVersionNumber() == minSdkVersion) { if (target.getVersion().equals(minSdkVersion)) {
mSdkTargetSelector.setSelection(target); mSdkTargetSelector.setSelection(target);
foundTarget = true; foundTarget = true;
break; break;
} }
} }
} catch(NumberFormatException e) {
// ignore
}
} }
if (!foundTarget) { if (!foundTarget) {
@@ -1059,9 +1051,9 @@ public class NewProjectCreationPage extends WizardPage {
if (!foundTarget) { if (!foundTarget) {
mInternalMinSdkVersionUpdate = true; mInternalMinSdkVersionUpdate = true;
mMinSdkVersionField.setText( if (minSdkVersion != null) {
minSdkVersion == AndroidManifestParser.INVALID_MIN_SDK ? "" //$NON-NLS-1$ mMinSdkVersionField.setText(minSdkVersion);
: Integer.toString(minSdkVersion)); }
mInternalMinSdkVersionUpdate = false; mInternalMinSdkVersionUpdate = false;
} }
} }
@@ -1269,21 +1261,10 @@ public class NewProjectCreationPage extends WizardPage {
return MSG_NONE; return MSG_NONE;
} }
int version = AndroidManifestParser.INVALID_MIN_SDK; if (mInfo.getSdkTarget() != null &&
try { mInfo.getSdkTarget().getVersion().equals(mInfo.getMinSdkVersion()) == false) {
// If not empty, it must be a valid integer > 0
version = Integer.parseInt(mInfo.getMinSdkVersion());
} catch (NumberFormatException e) {
// ignore
}
if (version < 1) {
return setStatus("Min SDK Version must be an integer > 0.", MSG_ERROR);
}
if (mInfo.getSdkTarget() != null && mInfo.getSdkTarget().getApiVersionNumber() != version) {
return setStatus("The API level for the selected SDK target does not match the Min SDK version.", return setStatus("The API level for the selected SDK target does not match the Min SDK version.",
MSG_WARNING); mInfo.getSdkTarget().getVersion().isPreview() ? MSG_ERROR : MSG_WARNING);
} }
return MSG_NONE; return MSG_NONE;

View File

@@ -821,7 +821,7 @@ public class NewTestProjectCreationPage extends WizardPage {
if (manifestData != null) { if (manifestData != null) {
String appName = String.format("%1$sTest", project.getName()); String appName = String.format("%1$sTest", project.getName());
String packageName = manifestData.getPackage(); String packageName = manifestData.getPackage();
int minSdkVersion = manifestData.getApiLevelRequirement(); String minSdkVersion = manifestData.getApiLevelRequirement();
IAndroidTarget sdkTarget = null; IAndroidTarget sdkTarget = null;
if (Sdk.getCurrent() != null) { if (Sdk.getCurrent() != null) {
sdkTarget = Sdk.getCurrent().getTarget(project); sdkTarget = Sdk.getCurrent().getTarget(project);
@@ -859,9 +859,9 @@ public class NewTestProjectCreationPage extends WizardPage {
if (!mMinSdkVersionModifiedByUser) { if (!mMinSdkVersionModifiedByUser) {
mInternalMinSdkVersionUpdate = true; mInternalMinSdkVersionUpdate = true;
mMinSdkVersionField.setText( if (minSdkVersion != null) {
minSdkVersion != AndroidManifestParser.INVALID_MIN_SDK ? mMinSdkVersionField.setText(minSdkVersion);
Integer.toString(minSdkVersion) : ""); //$NON-NLS-1$ }
if (sdkTarget == null) { if (sdkTarget == null) {
updateSdkSelectorToMatchMinSdkVersion(); updateSdkSelectorToMatchMinSdkVersion();
} }
@@ -1052,23 +1052,19 @@ public class NewTestProjectCreationPage extends WizardPage {
* that matches. * that matches.
*/ */
private void updateSdkSelectorToMatchMinSdkVersion() { private void updateSdkSelectorToMatchMinSdkVersion() {
try { String minSdkVersion = mInfo.getMinSdkVersion();
int version = Integer.parseInt(mInfo.getMinSdkVersion());
IAndroidTarget curr_target = mInfo.getSdkTarget(); IAndroidTarget curr_target = mInfo.getSdkTarget();
if (curr_target != null && curr_target.getApiVersionNumber() == version) { if (curr_target != null && curr_target.getVersion().equals(minSdkVersion)) {
return; return;
} }
for (IAndroidTarget target : mSdkTargetSelector.getTargets()) { for (IAndroidTarget target : mSdkTargetSelector.getTargets()) {
if (target.getApiVersionNumber() == version) { if (target.getVersion().equals(minSdkVersion)) {
mSdkTargetSelector.setSelection(target); mSdkTargetSelector.setSelection(target);
return; return;
} }
} }
} catch (NumberFormatException e) {
// ignore
}
} }
/** /**
@@ -1086,7 +1082,7 @@ public class NewTestProjectCreationPage extends WizardPage {
if (target != null) { if (target != null) {
mInternalMinSdkVersionUpdate = true; mInternalMinSdkVersionUpdate = true;
mMinSdkVersionField.setText(Integer.toString(target.getApiVersionNumber())); mMinSdkVersionField.setText(target.getVersion().getApiString());
mInternalMinSdkVersionUpdate = false; mInternalMinSdkVersionUpdate = false;
} }
@@ -1261,21 +1257,10 @@ public class NewTestProjectCreationPage extends WizardPage {
return MSG_NONE; return MSG_NONE;
} }
int version = AndroidManifestParser.INVALID_MIN_SDK; if (mInfo.getSdkTarget() != null &&
try { mInfo.getSdkTarget().getVersion().equals(mInfo.getMinSdkVersion()) == false) {
// If not empty, it must be a valid integer > 0
version = Integer.parseInt(mInfo.getMinSdkVersion());
} catch (NumberFormatException e) {
// ignore
}
if (version < 1) {
return setStatus("Min SDK Version must be an integer > 0.", MSG_ERROR);
}
if (mInfo.getSdkTarget() != null && mInfo.getSdkTarget().getApiVersionNumber() != version) {
return setStatus("The API level for the selected SDK target does not match the Min SDK version.", return setStatus("The API level for the selected SDK target does not match the Min SDK version.",
MSG_WARNING); mInfo.getSdkTarget().getVersion().isPreview() ? MSG_ERROR : MSG_WARNING);
} }
return MSG_NONE; return MSG_NONE;

View File

@@ -1130,7 +1130,7 @@ class NewXmlFileCreationPage extends WizardPage {
IAndroidTarget target = mProject != null ? Sdk.getCurrent().getTarget(mProject) : null; IAndroidTarget target = mProject != null ? Sdk.getCurrent().getTarget(mProject) : null;
int currentApiLevel = 1; int currentApiLevel = 1;
if (target != null) { if (target != null) {
currentApiLevel = target.getApiVersionNumber(); currentApiLevel = target.getVersion().getApiLevel();
} }
for (TypeInfo type : sTypes) { for (TypeInfo type : sTypes) {
@@ -1175,7 +1175,7 @@ class NewXmlFileCreationPage extends WizardPage {
IAndroidTarget target = Sdk.getCurrent().getTarget(mProject); IAndroidTarget target = Sdk.getCurrent().getTarget(mProject);
int currentApiLevel = 1; int currentApiLevel = 1;
if (target != null) { if (target != null) {
currentApiLevel = target.getApiVersionNumber(); currentApiLevel = target.getVersion().getApiLevel();
} }
TypeInfo type = getSelectedType(); TypeInfo type = getSelectedType();

View File

@@ -416,7 +416,7 @@ class Main {
mSdkLog.printf(" Name: %s\n", target.getName()); mSdkLog.printf(" Name: %s\n", target.getName());
if (target.isPlatform()) { if (target.isPlatform()) {
mSdkLog.printf(" Type: Platform\n"); mSdkLog.printf(" Type: Platform\n");
mSdkLog.printf(" API level: %d\n", target.getApiVersionNumber()); mSdkLog.printf(" API level: %s\n", target.getVersion().getApiString());
mSdkLog.printf(" Revision: %d\n", target.getRevision()); mSdkLog.printf(" Revision: %d\n", target.getRevision());
} else { } else {
mSdkLog.printf(" Type: Add-On\n"); mSdkLog.printf(" Type: Add-On\n");
@@ -426,7 +426,7 @@ class Main {
mSdkLog.printf(" Description: %s\n", target.getDescription()); mSdkLog.printf(" Description: %s\n", target.getDescription());
} }
mSdkLog.printf(" Based on Android %s (API level %d)\n", mSdkLog.printf(" Based on Android %s (API level %d)\n",
target.getApiVersionName(), target.getApiVersionNumber()); target.getVersionName(), target.getVersion().getApiString());
// display the optional libraries. // display the optional libraries.
IOptionalLibrary[] libraries = target.getOptionalLibraries(); IOptionalLibrary[] libraries = target.getOptionalLibraries();
@@ -501,13 +501,13 @@ class Main {
// get the target of the AVD // get the target of the AVD
IAndroidTarget target = info.getTarget(); IAndroidTarget target = info.getTarget();
if (target.isPlatform()) { if (target.isPlatform()) {
mSdkLog.printf(" Target: %s (API level %d)\n", target.getName(), mSdkLog.printf(" Target: %s (API level %s)\n", target.getName(),
target.getApiVersionNumber()); target.getVersion().getApiString());
} else { } else {
mSdkLog.printf(" Target: %s (%s)\n", target.getName(), target mSdkLog.printf(" Target: %s (%s)\n", target.getName(), target
.getVendor()); .getVendor());
mSdkLog.printf(" Based on Android %s (API level %d)\n", target mSdkLog.printf(" Based on Android %s (API level %s)\n",
.getApiVersionName(), target.getApiVersionNumber()); target.getVersionName(), target.getVersion().getApiString());
} }
// display some extra values. // display some extra values.

View File

@@ -137,14 +137,13 @@ final class AddOnTarget implements IAndroidTarget {
return mDescription; return mDescription;
} }
public String getApiVersionName() { public AndroidVersion getVersion() {
// this is always defined by the base platform // this is always defined by the base platform
return mBasePlatform.getApiVersionName(); return mBasePlatform.getVersion();
} }
public int getApiVersionNumber() { public String getVersionName() {
// this is always defined by the base platform return mBasePlatform.getVersionName();
return mBasePlatform.getApiVersionNumber();
} }
public int getRevision() { public int getRevision() {
@@ -182,7 +181,7 @@ final class AddOnTarget implements IAndroidTarget {
return sampleLoc.getAbsolutePath(); return sampleLoc.getAbsolutePath();
} }
} }
// INTENT FALL-THROUGH // INTENDED FALL-THROUGH
default : default :
return mBasePlatform.getPath(pathId); return mBasePlatform.getPath(pathId);
} }
@@ -222,21 +221,22 @@ final class AddOnTarget implements IAndroidTarget {
// if the receiver has no optional library, then anything with api version number >= to // if the receiver has no optional library, then anything with api version number >= to
// the receiver is compatible. // the receiver is compatible.
if (mLibraries.length == 0) { if (mLibraries.length == 0) {
return target.getApiVersionNumber() >= getApiVersionNumber(); return target.getVersion().getApiLevel() >= getVersion().getApiLevel();
} }
// Otherwise, target is only compatible if the vendor and name are equals with the api // Otherwise, target is only compatible if the vendor and name are equals with the api
// number greater or equal (ie target is a newer version of this add-on). // number greater or equal (ie target is a newer version of this add-on).
if (target.isPlatform() == false) { if (target.isPlatform() == false) {
return (mVendor.equals(target.getVendor()) && mName.equals(target.getName()) && return (mVendor.equals(target.getVendor()) && mName.equals(target.getName()) &&
target.getApiVersionNumber() >= getApiVersionNumber()); target.getVersion().getApiLevel() >= getVersion().getApiLevel());
} }
return false; return false;
} }
public String hashString() { public String hashString() {
return String.format(ADD_ON_FORMAT, mVendor, mName, mBasePlatform.getApiVersionNumber()); return String.format(ADD_ON_FORMAT, mVendor, mName,
mBasePlatform.getVersion().getApiLevel());
} }
@Override @Override
@@ -250,7 +250,7 @@ final class AddOnTarget implements IAndroidTarget {
AddOnTarget addon = (AddOnTarget)obj; AddOnTarget addon = (AddOnTarget)obj;
return mVendor.equals(addon.mVendor) && mName.equals(addon.mName) && return mVendor.equals(addon.mVendor) && mName.equals(addon.mName) &&
mBasePlatform.getApiVersionNumber() == addon.mBasePlatform.getApiVersionNumber(); mBasePlatform.getVersion().getApiLevel() == addon.mBasePlatform.getVersion().getApiLevel();
} }
return super.equals(obj); return super.equals(obj);
@@ -277,7 +277,7 @@ final class AddOnTarget implements IAndroidTarget {
// api version // api version
if (value == 0) { if (value == 0) {
value = getApiVersionNumber() - target.getApiVersionNumber(); value = getVersion().getApiLevel() - target.getVersion().getApiLevel();
} }
return value; return value;

View File

@@ -0,0 +1,179 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.sdklib;
import java.util.Properties;
/**
* Represents the version of a target or device.
* <p/>
* A version is defined by an API level and an optional code name.
* <ul><li>Release versions of the Android platform are identified by their API level (integer),
* (technically the code name for release version is "REL" but this class will return
* <code>null<code> instead.)</li>
* <li>Preview versions of the platform are identified by a code name. Their API level
* is usually set to the value of the previous platform.</li></ul>
* <p/>
* While this class contains both values, its goal is to abstract them, so that code comparing 2+
* versions doesn't have to deal with the logic of handle both values.
* <p/>
* There are some cases where ones may want to access the values directly. This can be done
* with {@link #getApiLevel()} and {@link #getCodename()}.
* <p/>
* For generic UI display of the API version, {@link #getApiString()} is to be used.
*
*/
public class AndroidVersion {
private static final String PROP_API_LEVEL = "AndroidVersion.ApiLevel"; //$NON-NLS-1$
private static final String PROP_CODENAME = "AndroidVersion.CodeName"; //$NON-NLS-1$
private final int mApiLevel;
private final String mCodename;
public AndroidVersion(int apiLevel, String codename) {
mApiLevel = apiLevel;
mCodename = codename;
}
public AndroidVersion(Properties properties) {
throw new UnsupportedOperationException("TODO");
}
public void saveProperties(Properties props) {
props.setProperty(PROP_API_LEVEL, Integer.toString(mApiLevel));
props.setProperty(PROP_CODENAME, mCodename);
}
/**
* Returns the api level as an integer.
* <p/>For target that are in preview mode, this can be superseded by
* {@link #getCodename()}.
* <p/>To display the API level in the UI, use {@link #getApiString()}, which will use the
* codename if applicable.
* @see #getCodename()
* @see #getApiString()
*/
public int getApiLevel() {
return mApiLevel;
}
/**
* Returns the version code name if applicable, null otherwise.
* <p/>If the codename is non null, then the API level should be ignored, and this should be
* used as a unique identifier of the target instead.
*/
public String getCodename() {
return mCodename;
}
/**
* Returns a string representing the API level and/or the code name.
*/
public String getApiString() {
if (mCodename != null) {
return mCodename;
}
return Integer.toString(mApiLevel);
}
/**
* Returns whether or not the version is a preview version.
*/
public boolean isPreview() {
return mCodename != null;
}
/**
* Checks whether a device running a version similar to the receiver can run a project compiled
* for the given <var>version</var>.
* <p/>
* Be aware that this is not a perfect test, as other properties could break compatibility
* despite this method returning true. For a more comprehensive test, see
* {@link IAndroidTarget#isCompatibleBaseFor(IAndroidTarget)}.
* <p/>
* Nevertheless, when testing if an application can run on a device (where there is no
* access to the list of optional libraries), this method can give a good indication of whether
* there is a chance the application could run, or if there's a direct incompatibility.
*/
public boolean canRun(AndroidVersion appVersion) {
// if the application is compiled for a preview version, the device must be running exactly
// the same.
if (appVersion.mCodename != null) {
return appVersion.mCodename.equals(mCodename);
}
// otherwise, we check the api level (note that a device running a preview version
// will have the api level of the previous platform).
return mApiLevel >= appVersion.mApiLevel;
}
/**
* Returns <code>true</code> if the AndroidVersion is an API level equals to
* <var>apiLevel</var>.
*/
public boolean equals(int apiLevel) {
return mCodename == null && apiLevel == mApiLevel;
}
/**
* Compares the receiver with either an {@link AndroidVersion} object or a {@link String}
* object.
* <p/>If <var>obj</var> is a {@link String}, then the method will first check if it's a string
* representation of a number, in which case it'll compare it to the api level. Otherwise, it'll
* compare it against the code name.
* <p/>For all other type of object give as parameter, this method will return
* <code>false</code>.
*/
@Override
public boolean equals(Object obj) {
if (obj instanceof AndroidVersion) {
AndroidVersion version = (AndroidVersion)obj;
if (mCodename == null) {
return version.mCodename == null &&
mApiLevel == version.mApiLevel;
} else {
return mCodename.equals(version.mCodename) &&
mApiLevel == version.mApiLevel;
}
} else if (obj instanceof String) {
try {
int value = Integer.parseInt((String)obj);
return value == mApiLevel;
} catch (NumberFormatException e) {
// not a number? compare to the code name
return obj.equals(mCodename);
}
}
return false;
}
@Override
public int hashCode() {
if (mCodename != null) {
return mCodename.hashCode();
}
// there may be some collisions between the hashcode of the codename and the api level
// but it's acceptable.
return mApiLevel;
}
}

View File

@@ -119,14 +119,14 @@ public interface IAndroidTarget extends Comparable<IAndroidTarget> {
String getDescription(); String getDescription();
/** /**
* Returns the api version as an integer. * Returns the version of the target. This is guaranteed to be non-null.
*/ */
int getApiVersionNumber(); AndroidVersion getVersion();
/** /**
* Returns the platform version as a readable string. * Returns the platform version as a readable string.
*/ */
String getApiVersionName(); public String getVersionName();
/** Returns the revision number for the target. */ /** Returns the revision number for the target. */
int getRevision(); int getRevision();

View File

@@ -26,32 +26,41 @@ import java.util.Map;
*/ */
final class PlatformTarget implements IAndroidTarget { final class PlatformTarget implements IAndroidTarget {
/** String used to get a hash to the platform target */ /** String used to get a hash to the platform target */
private final static String PLATFORM_HASH = "android-%d"; private final static String PLATFORM_HASH_API_LEVEL = "android-%d";
private final static String PLATFORM_HASH_CODENAME = "android-%s";
private final static String PLATFORM_VENDOR = "Android Open Source Project"; private final static String PLATFORM_VENDOR = "Android Open Source Project";
private final static String PLATFORM_NAME = "Android %s"; private final static String PLATFORM_NAME = "Android %s";
private final static String PLATFORM_NAME_PREVIEW = "Android %s (Preview)";
private final String mLocation; private final String mLocation;
private final String mName; private final String mName;
private final int mApiVersionNumber; private final AndroidVersion mVersion;
private final String mApiVersionName; private final String mVersionName;
private final int mRevision; private final int mRevision;
private final Map<String, String> mProperties; private final Map<String, String> mProperties;
private final Map<Integer, String> mPaths = new HashMap<Integer, String>(); private final Map<Integer, String> mPaths = new HashMap<Integer, String>();
private String[] mSkins; private String[] mSkins;
PlatformTarget(String location, Map<String, String> properties, PlatformTarget(String location, Map<String, String> properties,
int apiNumber, String apiName, int revision) { int apiLevel, String codeName, String versionName, int revision) {
mName = String.format(PLATFORM_NAME, apiName);
if (location.endsWith(File.separator) == false) { if (location.endsWith(File.separator) == false) {
location = location + File.separator; location = location + File.separator;
} }
mLocation = location; mLocation = location;
mProperties = Collections.unmodifiableMap(properties); mProperties = Collections.unmodifiableMap(properties);
mApiVersionNumber = apiNumber; mVersion = new AndroidVersion(apiLevel, codeName);
mApiVersionName = apiName; mVersionName = versionName;
mRevision = revision; mRevision = revision;
if (mVersion.isPreview()) {
mName = String.format(PLATFORM_NAME_PREVIEW, mVersionName);
} else {
mName = String.format(PLATFORM_NAME, mVersionName);
}
// pre-build the path to the platform components // pre-build the path to the platform components
mPaths.put(ANDROID_JAR, mLocation + SdkConstants.FN_FRAMEWORK_LIBRARY); mPaths.put(ANDROID_JAR, mLocation + SdkConstants.FN_FRAMEWORK_LIBRARY);
mPaths.put(SOURCES, mLocation + SdkConstants.FD_ANDROID_SOURCES); mPaths.put(SOURCES, mLocation + SdkConstants.FD_ANDROID_SOURCES);
@@ -119,15 +128,15 @@ final class PlatformTarget implements IAndroidTarget {
* @see com.android.sdklib.IAndroidTarget#getDescription() * @see com.android.sdklib.IAndroidTarget#getDescription()
*/ */
public String getDescription() { public String getDescription() {
return String.format("Standard Android platform %s", mApiVersionName); return String.format("Standard Android platform %s", mVersionName);
} }
public int getApiVersionNumber(){ public AndroidVersion getVersion() {
return mApiVersionNumber; return mVersion;
} }
public String getApiVersionName() { public String getVersionName() {
return mApiVersionName; return mVersionName;
} }
public int getRevision() { public int getRevision() {
@@ -189,13 +198,23 @@ final class PlatformTarget implements IAndroidTarget {
return true; return true;
} }
// if the platform has a codename (ie it's a preview of an upcoming platform), then
// both platform must be exactly identical.
if (mVersion.getCodename() != null) {
return equals(target);
}
// target is compatible wit the receiver as long as its api version number is greater or // target is compatible wit the receiver as long as its api version number is greater or
// equal. // equal.
return target.getApiVersionNumber() >= mApiVersionNumber; return target.getVersion().getApiLevel() >= mVersion.getApiLevel();
} }
public String hashString() { public String hashString() {
return String.format(PLATFORM_HASH, mApiVersionNumber); if (mVersion.getCodename() != null) {
return String.format(PLATFORM_HASH_CODENAME, mVersion.getCodename());
}
return String.format(PLATFORM_HASH_API_LEVEL, mVersion.getApiLevel());
} }
@Override @Override
@@ -206,10 +225,12 @@ final class PlatformTarget implements IAndroidTarget {
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (obj instanceof PlatformTarget) { if (obj instanceof PlatformTarget) {
return mApiVersionNumber == ((PlatformTarget)obj).mApiVersionNumber; PlatformTarget platform = (PlatformTarget)obj;
return mVersion.equals(platform.getVersion());
} }
return super.equals(obj); return false;
} }
/* /*
@@ -223,7 +244,13 @@ final class PlatformTarget implements IAndroidTarget {
return -1; return -1;
} }
return mApiVersionNumber - target.getApiVersionNumber(); int apiDiff = mVersion.getApiLevel() - target.getVersion().getApiLevel();
if (mVersion.getCodename() != null && apiDiff == 0) {
return mVersion.getCodename().compareTo(target.getVersion().getCodename());
}
return apiDiff;
} }
// ---- platform only methods. // ---- platform only methods.

View File

@@ -42,6 +42,7 @@ import java.util.regex.Pattern;
public final class SdkManager { public final class SdkManager {
public final static String PROP_VERSION_SDK = "ro.build.version.sdk"; public final static String PROP_VERSION_SDK = "ro.build.version.sdk";
public final static String PROP_VERSION_CODENAME = "ro.build.version.codename";
public final static String PROP_VERSION_RELEASE = "ro.build.version.release"; public final static String PROP_VERSION_RELEASE = "ro.build.version.release";
public final static String PROP_VERSION_REVISION = "ro.build.version.incremental"; public final static String PROP_VERSION_REVISION = "ro.build.version.incremental";
@@ -263,23 +264,28 @@ public final class SdkManager {
if (map != null) { if (map != null) {
// look for some specific values in the map. // look for some specific values in the map.
// version string
String apiName = map.get(PROP_VERSION_RELEASE); String apiName = map.get(PROP_VERSION_RELEASE);
if (apiName == null) { if (apiName == null) {
if (log != null) { if (log != null) {
log.error(null, log.error(null,
"Ignoring platform '%1$s': %2$s is missing from '%3$s'", "Ignoring platform '%1$s': %2$s is missing from '%3$s'",
platform.getName(), PROP_VERSION_RELEASE, SdkConstants.FN_BUILD_PROP); platform.getName(), PROP_VERSION_RELEASE,
SdkConstants.FN_BUILD_PROP);
} }
return null; return null;
} }
// api level
int apiNumber; int apiNumber;
String stringValue = map.get(PROP_VERSION_SDK); String stringValue = map.get(PROP_VERSION_SDK);
if (stringValue == null) { if (stringValue == null) {
if (log != null) { if (log != null) {
log.error(null, log.error(null,
"Ignoring platform '%1$s': %2$s is missing from '%3$s'", "Ignoring platform '%1$s': %2$s is missing from '%3$s'",
platform.getName(), PROP_VERSION_SDK, SdkConstants.FN_BUILD_PROP); platform.getName(), PROP_VERSION_SDK,
SdkConstants.FN_BUILD_PROP);
} }
return null; return null;
} else { } else {
@@ -291,19 +297,28 @@ public final class SdkManager {
if (log != null) { if (log != null) {
log.error(null, log.error(null,
"Ignoring platform '%1$s': %2$s is not a valid number in %3$s.", "Ignoring platform '%1$s': %2$s is not a valid number in %3$s.",
platform.getName(), PROP_VERSION_SDK, SdkConstants.FN_BUILD_PROP); platform.getName(), PROP_VERSION_SDK,
SdkConstants.FN_BUILD_PROP);
} }
return null; return null;
} }
} }
// codename (optional)
String apiCodename = map.get(PROP_VERSION_CODENAME);
if (apiCodename != null && apiCodename.equals("REL")) {
apiCodename = null; // REL means it's a release version and therefore the
// codename is irrelevant at this point.
}
int revision = 1; int revision = 1;
stringValue = map.get(PROP_VERSION_REVISION); stringValue = map.get(PROP_VERSION_REVISION);
if (stringValue == null) { if (stringValue == null) {
if (log != null) { if (log != null) {
log.error(null, log.error(null,
"Ignoring platform '%1$s': %2$s is missing from '%3$s'", "Ignoring platform '%1$s': %2$s is missing from '%3$s'",
platform.getName(), PROP_VERSION_REVISION, SdkConstants.FN_BUILD_PROP); platform.getName(), PROP_VERSION_REVISION,
SdkConstants.FN_BUILD_PROP);
} }
return null; return null;
} else { } else {
@@ -346,6 +361,7 @@ public final class SdkManager {
platform.getAbsolutePath(), platform.getAbsolutePath(),
map, map,
apiNumber, apiNumber,
apiCodename,
apiName, apiName,
revision); revision);
@@ -435,8 +451,7 @@ public final class SdkManager {
try { try {
int apiValue = Integer.parseInt(api); int apiValue = Integer.parseInt(api);
for (IAndroidTarget target : targetList) { for (IAndroidTarget target : targetList) {
if (target.isPlatform() && if (target.isPlatform() && target.getVersion().equals(apiValue)) {
target.getApiVersionNumber() == apiValue) {
baseTarget = (PlatformTarget)target; baseTarget = (PlatformTarget)target;
break; break;
} }

View File

@@ -16,6 +16,7 @@
package com.android.sdklib.internal.repository; package com.android.sdklib.internal.repository;
import com.android.sdklib.AndroidVersion;
import com.android.sdklib.IAndroidTarget; import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.SdkConstants; import com.android.sdklib.SdkConstants;
import com.android.sdklib.SdkManager; import com.android.sdklib.SdkManager;
@@ -36,13 +37,12 @@ import java.util.Properties;
*/ */
public class AddonPackage extends Package { public class AddonPackage extends Package {
private static final String PROP_API_LEVEL = "Addon.ApiLevel"; //$NON-NLS-1$
private static final String PROP_NAME = "Addon.Name"; //$NON-NLS-1$ private static final String PROP_NAME = "Addon.Name"; //$NON-NLS-1$
private static final String PROP_VENDOR = "Addon.Vendor"; //$NON-NLS-1$ private static final String PROP_VENDOR = "Addon.Vendor"; //$NON-NLS-1$
private final String mVendor; private final String mVendor;
private final String mName; private final String mName;
private final int mApiLevel; private final AndroidVersion mVersion;
/** An add-on library. */ /** An add-on library. */
public static class Lib { public static class Lib {
@@ -74,7 +74,10 @@ public class AddonPackage extends Package {
super(source, packageNode, licenses); super(source, packageNode, licenses);
mVendor = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_VENDOR); mVendor = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_VENDOR);
mName = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_NAME); mName = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_NAME);
mApiLevel = XmlParserUtils.getXmlInt (packageNode, SdkRepository.NODE_API_LEVEL, 0); mVersion = new AndroidVersion(
XmlParserUtils.getXmlInt (packageNode, SdkRepository.NODE_API_LEVEL, 0),
null); // add-ons on platform previews is not supported, so the codename is always
// null in this case.
mLibs = parseLibs(XmlParserUtils.getFirstChild(packageNode, SdkRepository.NODE_LIBS)); mLibs = parseLibs(XmlParserUtils.getFirstChild(packageNode, SdkRepository.NODE_LIBS));
} }
@@ -88,7 +91,7 @@ public class AddonPackage extends Package {
AddonPackage(IAndroidTarget target, Properties props) { AddonPackage(IAndroidTarget target, Properties props) {
super( null, //source super( null, //source
props, //properties props, //properties
0, //revision target.getRevision(), //revision
null, //license null, //license
target.getDescription(), //description target.getDescription(), //description
null, //descUrl null, //descUrl
@@ -97,7 +100,7 @@ public class AddonPackage extends Package {
target.getLocation() //archiveOsPath target.getLocation() //archiveOsPath
); );
mApiLevel = target.getApiVersionNumber(); mVersion = target.getVersion();
mName = target.getName(); mName = target.getName();
mVendor = target.getVendor(); mVendor = target.getVendor();
@@ -114,13 +117,13 @@ public class AddonPackage extends Package {
/** /**
* Save the properties of the current packages in the given {@link Properties} object. * Save the properties of the current packages in the given {@link Properties} object.
* These properties will later be give the constructor that takes a {@link Properties} object. * These properties will later be given to a constructor that takes a {@link Properties} object.
*/ */
@Override @Override
void saveProperties(Properties props) { void saveProperties(Properties props) {
super.saveProperties(props); super.saveProperties(props);
props.setProperty(PROP_API_LEVEL, Integer.toString(mApiLevel)); mVersion.saveProperties(props);
props.setProperty(PROP_NAME, mName); props.setProperty(PROP_NAME, mName);
props.setProperty(PROP_VENDOR, mVendor); props.setProperty(PROP_VENDOR, mVendor);
} }
@@ -167,7 +170,8 @@ public class AddonPackage extends Package {
/** Returns the api-level, an int > 0, for platform, add-on and doc packages. */ /** Returns the api-level, an int > 0, for platform, add-on and doc packages. */
public int getApiLevel() { public int getApiLevel() {
return mApiLevel; // FIXME: return the AndroidVersion instead.
return mVersion.getApiLevel();
} }
/** Returns the libs defined in this add-on. Can be an empty array but not null. */ /** Returns the libs defined in this add-on. Can be an empty array but not null. */
@@ -214,7 +218,7 @@ public class AddonPackage extends Package {
// First find if this add-on is already installed. If so, reuse the same directory. // First find if this add-on is already installed. If so, reuse the same directory.
for (IAndroidTarget target : sdkManager.getTargets()) { for (IAndroidTarget target : sdkManager.getTargets()) {
if (!target.isPlatform() && if (!target.isPlatform() &&
target.getApiVersionNumber() == getApiLevel() && target.getVersion().equals(mVersion) &&
target.getName().equals(getName()) && target.getName().equals(getName()) &&
target.getVendor().equals(getVendor())) { target.getVendor().equals(getVendor())) {
return new File(target.getLocation()); return new File(target.getLocation());

View File

@@ -16,6 +16,7 @@
package com.android.sdklib.internal.repository; package com.android.sdklib.internal.repository;
import com.android.sdklib.AndroidVersion;
import com.android.sdklib.IAndroidTarget; import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.SdkConstants; import com.android.sdklib.SdkConstants;
import com.android.sdklib.SdkManager; import com.android.sdklib.SdkManager;
@@ -34,11 +35,10 @@ import java.util.Properties;
*/ */
public class PlatformPackage extends Package { public class PlatformPackage extends Package {
private static final String PROP_API_LEVEL = "Platform.ApiLevel"; //$NON-NLS-1$
private static final String PROP_VERSION = "Platform.Version"; //$NON-NLS-1$ private static final String PROP_VERSION = "Platform.Version"; //$NON-NLS-1$
private final String mVersion; private final AndroidVersion mVersion;
private final int mApiLevel; private final String mVersionName;
/** /**
* Creates a new platform package from the attributes and elements of the given XML node. * Creates a new platform package from the attributes and elements of the given XML node.
@@ -47,8 +47,13 @@ public class PlatformPackage extends Package {
*/ */
PlatformPackage(RepoSource source, Node packageNode, Map<String,String> licenses) { PlatformPackage(RepoSource source, Node packageNode, Map<String,String> licenses) {
super(source, packageNode, licenses); super(source, packageNode, licenses);
mVersion = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_VERSION); mVersionName = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_VERSION);
mApiLevel = XmlParserUtils.getXmlInt (packageNode, SdkRepository.NODE_API_LEVEL, 0); int apiLevel = XmlParserUtils.getXmlInt (packageNode, SdkRepository.NODE_API_LEVEL, 0);
String codeName = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_API_CODENAME);
if (codeName.length() == 0) {
codeName = null;
}
mVersion = new AndroidVersion(apiLevel, codeName);
} }
/** /**
@@ -60,7 +65,7 @@ public class PlatformPackage extends Package {
PlatformPackage(IAndroidTarget target, Properties props) { PlatformPackage(IAndroidTarget target, Properties props) {
super( null, //source super( null, //source
props, //properties props, //properties
0, //revision target.getRevision(), //revision
null, //license null, //license
target.getDescription(), //description target.getDescription(), //description
null, //descUrl null, //descUrl
@@ -69,37 +74,43 @@ public class PlatformPackage extends Package {
target.getLocation() //archiveOsPath target.getLocation() //archiveOsPath
); );
mApiLevel = target.getApiVersionNumber(); mVersion = target.getVersion();
mVersion = target.getApiVersionName(); mVersionName = target.getVersionName();
} }
/** /**
* Save the properties of the current packages in the given {@link Properties} object. * Save the properties of the current packages in the given {@link Properties} object.
* These properties will later be give the constructor that takes a {@link Properties} object. * These properties will later be given to a constructor that takes a {@link Properties} object.
*/ */
@Override @Override
void saveProperties(Properties props) { void saveProperties(Properties props) {
super.saveProperties(props); super.saveProperties(props);
props.setProperty(PROP_API_LEVEL, Integer.toString(mApiLevel)); mVersion.saveProperties(props);
props.setProperty(PROP_VERSION, mVersion); props.setProperty(PROP_VERSION, mVersionName);
} }
/** Returns the version, a string, for platform packages. */ /** Returns the version, a string, for platform packages. */
public String getVersion() { public String getVersionName() {
return mVersion; return mVersionName;
} }
/** Returns the api-level, an int > 0, for platform, add-on and doc packages. */ /** Returns the api-level, an int > 0, for platform, add-on and doc packages. */
public int getApiLevel() { public int getApiLevel() {
return mApiLevel; // FIXME: return the AndroidVersion instead.
return mVersion.getApiLevel();
} }
/** Returns a short description for an {@link IDescription}. */ /** Returns a short description for an {@link IDescription}. */
@Override @Override
public String getShortDescription() { public String getShortDescription() {
if (mVersion.isPreview()) {
return String.format("SDK Platform Android %1$s (Preview)",
getVersionName());
}
return String.format("SDK Platform Android %1$s, API %2$d", return String.format("SDK Platform Android %1$s, API %2$d",
getVersion(), getVersionName(),
getApiLevel()); getApiLevel());
} }
@@ -128,17 +139,17 @@ public class PlatformPackage extends Package {
@Override @Override
public File getInstallFolder(String osSdkRoot, String suggestedDir, SdkManager sdkManager) { public File getInstallFolder(String osSdkRoot, String suggestedDir, SdkManager sdkManager) {
// First find if this add-on is already installed. If so, reuse the same directory. // First find if this platform is already installed. If so, reuse the same directory.
for (IAndroidTarget target : sdkManager.getTargets()) { for (IAndroidTarget target : sdkManager.getTargets()) {
if (target.isPlatform() && if (target.isPlatform() &&
target.getApiVersionNumber() == getApiLevel() && target.getVersion().equals(mVersion) &&
target.getApiVersionName().equals(getVersion())) { target.getVersionName().equals(getVersionName())) {
return new File(target.getLocation()); return new File(target.getLocation());
} }
} }
File platforms = new File(osSdkRoot, SdkConstants.FD_PLATFORMS); File platforms = new File(osSdkRoot, SdkConstants.FD_PLATFORMS);
File folder = new File(platforms, String.format("android-%s", getVersion())); //$NON-NLS-1$ File folder = new File(platforms, String.format("android-%s", getVersionName())); //$NON-NLS-1$
return folder; return folder;
} }
@@ -162,7 +173,7 @@ public class PlatformPackage extends Package {
} }
PlatformPackage newPkg = (PlatformPackage) replacementPackage; PlatformPackage newPkg = (PlatformPackage) replacementPackage;
return newPkg.getVersion().equalsIgnoreCase(this.getVersion()) && return newPkg.getVersionName().equalsIgnoreCase(this.getVersionName()) &&
newPkg.getApiLevel() == this.getApiLevel() && newPkg.getApiLevel() == this.getApiLevel() &&
newPkg.getRevision() > this.getRevision(); newPkg.getRevision() > this.getRevision();
} }

View File

@@ -63,6 +63,8 @@ public class SdkRepository {
public static final String NODE_VERSION = "version"; //$NON-NLS-1$ public static final String NODE_VERSION = "version"; //$NON-NLS-1$
/** The api-level, an int > 0, for platform, add-on and doc packages. */ /** The api-level, an int > 0, for platform, add-on and doc packages. */
public static final String NODE_API_LEVEL = "api-level"; //$NON-NLS-1$ public static final String NODE_API_LEVEL = "api-level"; //$NON-NLS-1$
/** The api-codename, a string, for platform packages. */
public static final String NODE_API_CODENAME = "api-codename"; //$NON-NLS-1$
/** The vendor, a string, for add-on packages. */ /** The vendor, a string, for add-on packages. */
public static final String NODE_VENDOR = "vendor"; //$NON-NLS-1$ public static final String NODE_VENDOR = "vendor"; //$NON-NLS-1$
/** The name, a string, for add-on packages or for libraries. */ /** The name, a string, for add-on packages or for libraries. */

View File

@@ -52,6 +52,8 @@
<xsd:element name="version" type="xsd:normalizedString" /> <xsd:element name="version" type="xsd:normalizedString" />
<!-- The Android API Level for the platform. An int > 0. --> <!-- The Android API Level for the platform. An int > 0. -->
<xsd:element name="api-level" type="xsd:positiveInteger" /> <xsd:element name="api-level" type="xsd:positiveInteger" />
<!-- The optional codename for this platform, if it's a preview. -->
<xsd:element name="api-codename" type="xsd:string" minOccurs="0" />
<!-- The revision, an int > 0, incremented each time a new <!-- The revision, an int > 0, incremented each time a new
package is generated. --> package is generated. -->

View File

@@ -157,6 +157,24 @@
<sdk:uses-license ref="license2" /> <sdk:uses-license ref="license2" />
</sdk:add-on> </sdk:add-on>
<sdk:platform>
<sdk:version>Pastry</sdk:version>
<sdk:api-level>5</sdk:api-level>
<sdk:api-codename>Pastry</sdk:api-codename>
<sdk:revision>3</sdk:revision>
<sdk:uses-license ref="license1" />
<sdk:description>Preview version for Pastry</sdk:description>
<sdk:desc-url>http://www.example.com/platform1.html</sdk:desc-url>
<!-- The archives node is mandatory and it cannot be empty. -->
<sdk:archives>
<sdk:archive os="any">
<sdk:size>65536</sdk:size>
<sdk:checksum type="sha1">2822ae37115ebf13412bbef91339ee0d9454525e</sdk:checksum>
<sdk:url>http://www.example.com/files/plat1.zip</sdk:url>
</sdk:archive>
</sdk:archives>
</sdk:platform>
<sdk:tool> <sdk:tool>
<sdk:revision>1</sdk:revision> <sdk:revision>1</sdk:revision>
<sdk:description>Some optional description</sdk:description> <sdk:description>Some optional description</sdk:description>

View File

@@ -273,14 +273,14 @@ final class AvdCreationDialog extends Dialog {
for (IAndroidTarget target : sdkManager.getTargets()) { for (IAndroidTarget target : sdkManager.getTargets()) {
String name; String name;
if (target.isPlatform()) { if (target.isPlatform()) {
name = String.format("%s - API Level %d", name = String.format("%s - API Level %s",
target.getName(), target.getName(),
target.getApiVersionNumber()); target.getVersion().getApiString());
} else { } else {
name = String.format("%s (%s) - API Level %d", name = String.format("%s (%s) - API Level %s",
target.getName(), target.getName(),
target.getVendor(), target.getVendor(),
target.getApiVersionNumber()); target.getVersion().getApiString());
} }
mCurrentTargets.put(name, target); mCurrentTargets.put(name, target);
mTargetCombo.add(name); mTargetCombo.add(name);

View File

@@ -16,6 +16,7 @@
package com.android.sdkuilib.internal.widgets; package com.android.sdkuilib.internal.widgets;
import com.android.sdklib.AndroidVersion;
import com.android.sdklib.IAndroidTarget; import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.internal.avd.AvdManager; import com.android.sdklib.internal.avd.AvdManager;
import com.android.sdklib.internal.avd.AvdManager.AvdInfo; import com.android.sdklib.internal.avd.AvdManager.AvdInfo;
@@ -106,8 +107,9 @@ final class AvdDetailsDialog extends Dialog {
displayValue(c, "Error:", mAvdInfo.getErrorMessage()); displayValue(c, "Error:", mAvdInfo.getErrorMessage());
} else { } else {
IAndroidTarget target = mAvdInfo.getTarget(); IAndroidTarget target = mAvdInfo.getTarget();
displayValue(c, "Target:", String.format("%s (API level %d)", AndroidVersion version = target.getVersion();
target.getName(), target.getApiVersionNumber())); displayValue(c, "Target:", String.format("%s (API level %s)",
target.getName(), version.getApiString()));
// display some extra values. // display some extra values.
Map<String, String> properties = mAvdInfo.getProperties(); Map<String, String> properties = mAvdInfo.getProperties();

View File

@@ -723,8 +723,8 @@ public final class AvdSelector {
IAndroidTarget target = avd.getTarget(); IAndroidTarget target = avd.getTarget();
if (target != null) { if (target != null) {
item.setText(1, target.getFullName()); item.setText(1, target.getFullName());
item.setText(2, target.getApiVersionName()); item.setText(2, target.getVersionName());
item.setText(3, Integer.toString(target.getApiVersionNumber())); item.setText(3, target.getVersion().getApiString());
} else { } else {
item.setText(1, "?"); item.setText(1, "?");
item.setText(2, "?"); item.setText(2, "?");

View File

@@ -323,8 +323,8 @@ public class SdkTargetSelector {
item.setData(target); item.setData(target);
item.setText(0, target.getName()); item.setText(0, target.getName());
item.setText(1, target.getVendor()); item.setText(1, target.getVendor());
item.setText(2, target.getApiVersionName()); item.setText(2, target.getVersionName());
item.setText(3, Integer.toString(target.getApiVersionNumber())); item.setText(3, target.getVersion().getApiString());
} }
} else { } else {
table.setEnabled(false); table.setEnabled(false);