aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--anttasks/src/com/android/ant/SetupTask.java34
-rwxr-xr-xddms/libs/ddmlib/src/com/android/ddmlib/IDevice.java8
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/PreCompilerBuilder.java223
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/PreCompilerDeltaVisitor.java44
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/AndroidLaunchController.java110
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/DelayedLaunchInfo.java49
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/DeviceChooserDialog.java32
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidManifestParser.java37
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetParser.java118
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java17
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectCreationPage.java73
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewTestProjectCreationPage.java49
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java140
-rw-r--r--sdkmanager/app/src/com/android/sdkmanager/Main.java12
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java22
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/AndroidVersion.java179
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java6
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java61
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java27
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonPackage.java22
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/PlatformPackage.java51
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/repository/SdkRepository.java2
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/repository/sdk-repository.xsd2
-rwxr-xr-xsdkmanager/libs/sdklib/tests/com/android/sdklib/repository/repository_sample.xml18
-rw-r--r--sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdCreationDialog.java8
-rw-r--r--sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdDetailsDialog.java6
-rw-r--r--sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java4
-rw-r--r--sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/SdkTargetSelector.java4
28 files changed, 827 insertions, 531 deletions
diff --git a/anttasks/src/com/android/ant/SetupTask.java b/anttasks/src/com/android/ant/SetupTask.java
index 60f8c7e..7af9611 100644
--- a/anttasks/src/com/android/ant/SetupTask.java
+++ b/anttasks/src/com/android/ant/SetupTask.java
@@ -44,13 +44,13 @@ import java.util.HashSet;
* <li>Imports the build rules located in the resolved target so that the build actually does
* something. This can be disabled with the attribute <var>import</var> set to <code>false</code>
* </li></ul>
- *
+ *
* This is used in build.xml/template.
*
*/
public final class SetupTask extends ImportTask {
private final static String ANDROID_RULES = "android_rules.xml";
-
+
// ant property with the path to the android.jar
private final static String PROPERTY_ANDROID_JAR = "android-jar";
// ant property with the path to the framework.jar
@@ -63,21 +63,21 @@ public final class SetupTask extends ImportTask {
private final static String PROPERTY_DX = "dx";
// ref id to the <path> object containing all the boot classpaths.
private final static String REF_CLASSPATH = "android.target.classpath";
-
+
private boolean mDoImport = true;
@Override
public void execute() throws BuildException {
Project antProject = getProject();
-
+
// get the SDK location
String sdkLocation = antProject.getProperty(ProjectProperties.PROPERTY_SDK);
-
+
// check if it's valid and exists
if (sdkLocation == null || sdkLocation.length() == 0) {
throw new BuildException("SDK Location is not set.");
}
-
+
File sdk = new File(sdkLocation);
if (sdk.isDirectory() == false) {
throw new BuildException(String.format("SDK Location '%s' is not valid.", sdkLocation));
@@ -120,20 +120,20 @@ public final class SetupTask extends ImportTask {
// resolve it
IAndroidTarget androidTarget = manager.getTargetFromHashString(targetHashString);
-
+
if (androidTarget == null) {
throw new BuildException(String.format(
"Unable to resolve target '%s'", targetHashString));
}
-
+
// display it
System.out.println("Project Target: " + androidTarget.getName());
if (androidTarget.isPlatform() == false) {
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
String androidJar = androidTarget.getPath(IAndroidTarget.ANDROID_JAR);
antProject.setProperty(PROPERTY_ANDROID_JAR, androidJar);
@@ -152,7 +152,7 @@ public final class SetupTask extends ImportTask {
// create a PathElement for the framework jar
PathElement element = bootclasspath.createPathElement();
element.setPath(androidJar);
-
+
// create PathElement for each optional library.
IOptionalLibrary[] libraries = androidTarget.getOptionalLibraries();
if (libraries != null) {
@@ -167,13 +167,13 @@ public final class SetupTask extends ImportTask {
}
}
}
-
+
// finally sets the path in the project with a reference
antProject.addReference(REF_CLASSPATH, bootclasspath);
// find the file to import, and import it.
String templateFolder = androidTarget.getPath(IAndroidTarget.TEMPLATES);
-
+
// Now the import section. This is only executed if the task actually has to import a file.
if (mDoImport) {
// make sure the file exists.
@@ -182,17 +182,17 @@ public final class SetupTask extends ImportTask {
throw new BuildException(String.format("Template directory '%s' is missing.",
templateFolder));
}
-
+
// now check the rules file exists.
File rules = new File(templateFolder, ANDROID_RULES);
if (rules.isFile() == false) {
throw new BuildException(String.format("Build rules file '%s' is missing.",
templateFolder));
}
-
+
// set the file location to import
setFile(rules.getAbsolutePath());
-
+
// and import
super.execute();
}
diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/IDevice.java b/ddms/libs/ddmlib/src/com/android/ddmlib/IDevice.java
index 7e90878..8096abd 100755
--- a/ddms/libs/ddmlib/src/com/android/ddmlib/IDevice.java
+++ b/ddms/libs/ddmlib/src/com/android/ddmlib/IDevice.java
@@ -28,8 +28,11 @@ import java.util.Map;
public interface IDevice {
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";
+
/** Serial number of the first connected emulator. */
public final static String FIRST_EMULATOR_SN = "emulator-5554"; //$NON-NLS-1$
/** Device change bit mask: {@link DeviceState} change. */
@@ -39,6 +42,9 @@ public interface IDevice {
/** Device change bit mask: build info change. */
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.
*/
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/PreCompilerBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/PreCompilerBuilder.java
index 711708f..c7fd289 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/PreCompilerBuilder.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/PreCompilerBuilder.java
@@ -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.XmlErrorHandler.BasicXmlErrorListener;
import com.android.ide.eclipse.adt.internal.sdk.Sdk;
+import com.android.sdklib.AndroidVersion;
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.SdkConstants;
@@ -89,22 +90,22 @@ public class PreCompilerBuilder extends BaseBuilder {
this.sourceFolder = sourceFolder;
this.aidlFile = aidlFile;
}
-
+
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
-
+
if (obj instanceof AidlData) {
AidlData file = (AidlData)obj;
return aidlFile.equals(file.aidlFile) && sourceFolder.equals(file.sourceFolder);
}
-
+
return false;
}
}
-
+
/**
* Resource Compile flag. This flag is reset to false after each successful compilation, and
* stored in the project persistent properties. This allows the builder to remember its state
@@ -120,7 +121,7 @@ public class PreCompilerBuilder extends BaseBuilder {
/** cache of the java package defined in the manifest */
private String mManifestPackage;
-
+
/** Output folder for generated Java File. Created on the Builder init
* @see #startupOnInitialize()
*/
@@ -145,11 +146,11 @@ public class PreCompilerBuilder extends BaseBuilder {
private boolean mDone = false;
public DerivedProgressMonitor() {
}
-
+
void addFile(IFile file) {
mFileList.add(file);
}
-
+
void reset() {
mFileList.clear();
mDone = false;
@@ -198,7 +199,7 @@ public class PreCompilerBuilder extends BaseBuilder {
public PreCompilerBuilder() {
super();
}
-
+
// build() returns a list of project from which this project depends for future compilation.
@SuppressWarnings("unchecked")
@Override
@@ -209,24 +210,24 @@ public class PreCompilerBuilder extends BaseBuilder {
// First thing we do is go through the resource delta to not
// lose it if we have to abort the build for any reason.
-
+
// get the project objects
IProject project = getProject();
-
+
// Top level check to make sure the build can move forward.
abortOnBadSetup(project);
-
+
IJavaProject javaProject = JavaCore.create(project);
IAndroidTarget projectTarget = Sdk.getCurrent().getTarget(project);
-
+
// now we need to get the classpath list
ArrayList<IPath> sourceFolderPathList = BaseProjectHelper.getSourceClasspaths(
javaProject);
-
+
PreCompilerDeltaVisitor dv = null;
String javaPackage = null;
- int minSdkVersion = AndroidManifestParser.INVALID_MIN_SDK;
-
+ String minSdkVersion = null;
+
if (kind == FULL_BUILD) {
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
Messages.Start_Full_Pre_Compiler);
@@ -235,7 +236,7 @@ public class PreCompilerBuilder extends BaseBuilder {
} else {
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
Messages.Start_Inc_Pre_Compiler);
-
+
// Go through the resources and see if something changed.
// Even if the mCompileResources flag is true from a previously aborted
// build, we need to go through the Resource delta to get a possible
@@ -247,10 +248,10 @@ public class PreCompilerBuilder extends BaseBuilder {
} else {
dv = new PreCompilerDeltaVisitor(this, sourceFolderPathList);
delta.accept(dv);
-
+
// record the state
mMustCompileResources |= dv.getCompileResources();
-
+
if (dv.getForceAidlCompile()) {
buildAidlCompilationList(project, sourceFolderPathList);
} else {
@@ -258,46 +259,46 @@ public class PreCompilerBuilder extends BaseBuilder {
mergeAidlFileModifications(dv.getAidlToCompile(),
dv.getAidlToRemove());
}
-
+
// get the java package from the visitor
javaPackage = dv.getManifestPackage();
minSdkVersion = dv.getMinSdkVersion();
}
}
-
+
// store the build status in the persistent storage
saveProjectBooleanProperty(PROPERTY_COMPILE_RESOURCES , mMustCompileResources);
-
+
// if there was some XML errors, we just return w/o doing
// anything since we've put some markers in the files anyway.
if (dv != null && dv.mXmlError) {
AdtPlugin.printErrorToConsole(project, Messages.Xml_Error);
-
+
// This interrupts the build. The next builders will not run.
stopBuild(Messages.Xml_Error);
}
-
-
+
+
// get the manifest file
IFile manifest = AndroidManifestParser.getManifest(project);
-
+
if (manifest == null) {
String msg = String.format(Messages.s_File_Missing,
AndroidConstants.FN_ANDROID_MANIFEST);
AdtPlugin.printErrorToConsole(project, msg);
markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR);
-
+
// This interrupts the build. The next builders will not run.
stopBuild(msg);
}
-
+
// lets check the XML of the manifest first, if that hasn't been done by the
// resource delta visitor yet.
if (dv == null || dv.getCheckedManifestXml() == false) {
BasicXmlErrorListener errorListener = new BasicXmlErrorListener();
AndroidManifestParser parser = BaseProjectHelper.parseManifestForError(manifest,
errorListener);
-
+
if (errorListener.mHasXmlError == true) {
// there was an error in the manifest, its file has been marked,
// by the XmlErrorHandler.
@@ -305,25 +306,71 @@ public class PreCompilerBuilder extends BaseBuilder {
String msg = String.format(Messages.s_Contains_Xml_Error,
AndroidConstants.FN_ANDROID_MANIFEST);
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg);
-
+
// This interrupts the build. The next builders will not run.
stopBuild(msg);
}
-
+
// get the java package from the parser
javaPackage = parser.getPackage();
minSdkVersion = parser.getApiLevelRequirement();
}
- if (minSdkVersion != AndroidManifestParser.INVALID_MIN_SDK &&
- minSdkVersion < projectTarget.getApiVersionNumber()) {
- // check it against the target api level
- String msg = String.format(
- "Manifest min SDK version (%1$d) is lower than project target API level (%2$d)",
- minSdkVersion, projectTarget.getApiVersionNumber());
- AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg);
- BaseProjectHelper.addMarker(manifest, AdtConstants.MARKER_ADT, msg,
- IMarker.SEVERITY_WARNING);
+ if (minSdkVersion != null) {
+ int minSdkValue = -1;
+ 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(
+ "Manifest min SDK version (%1$d) is lower than project target API level (%2$d)",
+ minSdkVersion, projectVersion.getApiLevel());
+ AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg);
+ BaseProjectHelper.addMarker(manifest, AdtConstants.MARKER_ADT, msg,
+ 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) {
@@ -332,11 +379,11 @@ public class PreCompilerBuilder extends BaseBuilder {
AndroidConstants.FN_ANDROID_MANIFEST);
AdtPlugin.printErrorToConsole(project, msg);
markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR);
-
+
// This interrupts the build. The next builders will not run.
stopBuild(msg);
}
-
+
// at this point we have the java package. We need to make sure it's not a different
// package than the previous one that were built.
if (javaPackage.equals(mManifestPackage) == false) {
@@ -345,64 +392,64 @@ public class PreCompilerBuilder extends BaseBuilder {
if (mManifestPackage != null) {
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
Messages.Checking_Package_Change);
-
+
FixLaunchConfig flc = new FixLaunchConfig(project, mManifestPackage,
javaPackage);
flc.start();
}
-
+
// now we delete the generated classes from their previous location
deleteObsoleteGeneratedClass(AndroidConstants.FN_RESOURCE_CLASS,
mManifestPackage);
deleteObsoleteGeneratedClass(AndroidConstants.FN_MANIFEST_CLASS,
mManifestPackage);
-
+
// record the new manifest package, and save it.
mManifestPackage = javaPackage;
saveProjectStringProperty(PROPERTY_PACKAGE, mManifestPackage);
}
-
+
if (mMustCompileResources) {
// we need to figure out where to store the R class.
// get the parent folder for R.java and update mManifestPackageSourceFolder
IFolder packageFolder = getGenManifestPackageFolder(project);
-
+
// get the resource folder
IFolder resFolder = project.getFolder(AndroidConstants.WS_RESOURCES);
-
+
// get the file system path
IPath outputLocation = mGenFolder.getLocation();
IPath resLocation = resFolder.getLocation();
IPath manifestLocation = manifest.getLocation();
-
+
// those locations have to exist for us to do something!
if (outputLocation != null && resLocation != null
&& manifestLocation != null) {
String osOutputPath = outputLocation.toOSString();
String osResPath = resLocation.toOSString();
String osManifestPath = manifestLocation.toOSString();
-
+
// remove the aapt markers
removeMarkersFromFile(manifest, AndroidConstants.MARKER_AAPT_COMPILE);
removeMarkersFromContainer(resFolder, AndroidConstants.MARKER_AAPT_COMPILE);
-
+
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
Messages.Preparing_Generated_Files);
-
+
// since the R.java file may be already existing in read-only
// mode we need to make it readable so that aapt can overwrite
// it
IFile rJavaFile = packageFolder.getFile(AndroidConstants.FN_RESOURCE_CLASS);
-
+
// do the same for the Manifest.java class
IFile manifestJavaFile = packageFolder.getFile(
AndroidConstants.FN_MANIFEST_CLASS);
-
+
// we actually need to delete the manifest.java as it may become empty and
// in this case aapt doesn't generate an empty one, but instead doesn't
// touch it.
manifestJavaFile.delete(true, null);
-
+
// launch aapt: create the command line
ArrayList<String> array = new ArrayList<String>();
array.add(projectTarget.getPath(IAndroidTarget.AAPT));
@@ -419,7 +466,7 @@ public class PreCompilerBuilder extends BaseBuilder {
array.add(osResPath);
array.add("-I"); //$NON-NLS-1$
array.add(projectTarget.getPath(IAndroidTarget.ANDROID_JAR));
-
+
if (AdtPlugin.getBuildVerbosity() == AdtConstants.BUILD_VERBOSE) {
StringBuilder sb = new StringBuilder();
for (String c : array) {
@@ -429,23 +476,23 @@ public class PreCompilerBuilder extends BaseBuilder {
String cmd_line = sb.toString();
AdtPlugin.printToConsole(project, cmd_line);
}
-
+
// launch
int execError = 1;
try {
// launch the command line process
Process process = Runtime.getRuntime().exec(
array.toArray(new String[array.size()]));
-
+
// list to store each line of stderr
ArrayList<String> results = new ArrayList<String>();
-
+
// get the output and return code from the process
execError = grabProcessOutput(process, results);
-
+
// attempt to parse the error output
boolean parsingError = parseAaptOutput(results, project);
-
+
// if we couldn't parse the output we display it in the console.
if (parsingError) {
if (execError != 0) {
@@ -455,7 +502,7 @@ public class PreCompilerBuilder extends BaseBuilder {
project, results.toArray());
}
}
-
+
if (execError != 0) {
// if the exec failed, and we couldn't parse the error output
// (and therefore not all files that should have been marked,
@@ -464,10 +511,10 @@ public class PreCompilerBuilder extends BaseBuilder {
markProject(AdtConstants.MARKER_ADT, Messages.Unparsed_AAPT_Errors,
IMarker.SEVERITY_ERROR);
}
-
+
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
Messages.AAPT_Error);
-
+
// abort if exec failed.
// This interrupts the build. The next builders will not run.
stopBuild(Messages.AAPT_Error);
@@ -477,7 +524,7 @@ public class PreCompilerBuilder extends BaseBuilder {
// mark the project and exit
String msg = String.format(Messages.AAPT_Exec_Error, array.get(0));
markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR);
-
+
// This interrupts the build. The next builders will not run.
stopBuild(msg);
} catch (InterruptedException e) {
@@ -485,11 +532,11 @@ public class PreCompilerBuilder extends BaseBuilder {
// mark the project and exit
String msg = String.format(Messages.AAPT_Exec_Error, array.get(0));
markProject(AdtConstants.MARKER_ADT, msg, IMarker.SEVERITY_ERROR);
-
+
// This interrupts the build. The next builders will not run.
stopBuild(msg);
}
-
+
// if the return code was OK, we refresh the folder that
// contains R.java to force a java recompile.
if (execError == 0) {
@@ -497,10 +544,10 @@ public class PreCompilerBuilder extends BaseBuilder {
// as derived.
mDerivedProgressMonitor.addFile(rJavaFile);
mDerivedProgressMonitor.addFile(manifestJavaFile);
-
+
// build has been done. reset the state of the builder
mMustCompileResources = false;
-
+
// and store it
saveProjectBooleanProperty(PROPERTY_COMPILE_RESOURCES,
mMustCompileResources);
@@ -509,10 +556,10 @@ public class PreCompilerBuilder extends BaseBuilder {
} else {
// nothing to do
}
-
+
// now handle the aidl stuff.
boolean aidlStatus = handleAidl(projectTarget, sourceFolderPathList, monitor);
-
+
if (aidlStatus == false && mMustCompileResources == false) {
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
Messages.Nothing_To_Compile);
@@ -540,14 +587,14 @@ public class PreCompilerBuilder extends BaseBuilder {
@Override
protected void startupOnInitialize() {
super.startupOnInitialize();
-
+
mDerivedProgressMonitor = new DerivedProgressMonitor();
-
+
IProject project = getProject();
// load the previous IFolder and java package.
mManifestPackage = loadProjectStringProperty(PROPERTY_PACKAGE);
-
+
// get the source folder in which all the Java files are created
mGenFolder = project.getFolder(SdkConstants.FD_GEN_SOURCES);
@@ -555,14 +602,14 @@ public class PreCompilerBuilder extends BaseBuilder {
// recompile.
mMustCompileResources = loadProjectBooleanProperty(PROPERTY_COMPILE_RESOURCES, true);
boolean mustCompileAidl = loadProjectBooleanProperty(PROPERTY_COMPILE_AIDL, true);
-
+
// if we stored that we have to compile some aidl, we build the list that will compile them
// all
if (mustCompileAidl) {
IJavaProject javaProject = JavaCore.create(project);
ArrayList<IPath> sourceFolderPathList = BaseProjectHelper.getSourceClasspaths(
javaProject);
-
+
buildAidlCompilationList(project, sourceFolderPathList);
}
}
@@ -576,7 +623,7 @@ public class PreCompilerBuilder extends BaseBuilder {
if (javaPackage == null) {
return;
}
-
+
IPath packagePath = getJavaPackagePath(javaPackage);
IPath iPath = packagePath.append(filename);
@@ -614,10 +661,10 @@ public class PreCompilerBuilder extends BaseBuilder {
path.append(AndroidConstants.WS_SEP_CHAR);
path.append(s);
}
-
+
return new Path(path.toString());
}
-
+
/**
* Returns an {@link IFolder} (located inside the 'gen' source folder), that matches the
* package defined in the manifest. This {@link IFolder} may not actually exist
@@ -630,7 +677,7 @@ public class PreCompilerBuilder extends BaseBuilder {
throws CoreException {
// get the path for the package
IPath packagePath = getJavaPackagePath(mManifestPackage);
-
+
// get a folder for this path under the 'gen' source folder, and return it.
// This IFolder may not reference an actual existing folder.
return mGenFolder.getFolder(packagePath);
@@ -657,10 +704,10 @@ public class PreCompilerBuilder extends BaseBuilder {
command[index++] = projectTarget.getPath(IAndroidTarget.AIDL);
command[index++] = "-p" + Sdk.getCurrent().getTarget(getProject()).getPath( //$NON-NLS-1$
IAndroidTarget.ANDROID_AIDL);
-
+
// since the path are relative to the workspace and not the project itself, we need
// the workspace root.
- IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot();
+ IWorkspaceRoot wsRoot = ResourcesPlugin.getWorkspace().getRoot();
for (IPath p : sourceFolders) {
IFolder f = wsRoot.getFolder(p);
command[index++] = "-I" + f.getLocation().toOSString(); //$NON-NLS-1$
@@ -686,7 +733,7 @@ public class PreCompilerBuilder extends BaseBuilder {
// get the path of the source file.
IPath sourcePath = aidlData.aidlFile.getLocation();
String osSourcePath = sourcePath.toOSString();
-
+
IFile javaFile = getGenDestinationFile(aidlData, true /*createFolders*/, monitor);
// finish to set the command line.
@@ -755,15 +802,15 @@ public class PreCompilerBuilder extends BaseBuilder {
IPath packagePath = aidlData.aidlFile.getFullPath().removeFirstSegments(
segmentToSourceFolderCount).removeLastSegments(1);
Path destinationPath = new Path(packagePath.toString());
-
+
// get an IFolder for this path. It's relative to the 'gen' folder already
IFolder destinationFolder = mGenFolder.getFolder(destinationPath);
-
+
// create it if needed.
if (destinationFolder.exists() == false && createFolders) {
createFolder(destinationFolder, monitor);
}
-
+
// Build the Java file name from the aidl name.
String javaName = aidlData.aidlFile.getName().replaceAll(AndroidConstants.RE_AIDL_EXT,
AndroidConstants.DOT_JAVA);
@@ -776,15 +823,15 @@ public class PreCompilerBuilder extends BaseBuilder {
/**
* Creates the destination folder. Because
* {@link IFolder#create(boolean, boolean, IProgressMonitor)} only works if the parent folder
- * already exists, this goes and ensure that all the parent folders actually exist, or it
+ * already exists, this goes and ensure that all the parent folders actually exist, or it
* creates them as well.
* @param destinationFolder The folder to create
* @param monitor the {@link IProgressMonitor},
- * @throws CoreException
+ * @throws CoreException
*/
private void createFolder(IFolder destinationFolder, IProgressMonitor monitor)
throws CoreException {
-
+
// check the parent exist and create if necessary.
IContainer parent = destinationFolder.getParent();
if (parent.getType() == IResource.FOLDER && parent.exists() == false) {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/PreCompilerDeltaVisitor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/PreCompilerDeltaVisitor.java
index 38ff480..d5e6365 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/PreCompilerDeltaVisitor.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/PreCompilerDeltaVisitor.java
@@ -44,16 +44,16 @@ import java.util.ArrayList;
* {@link PreCompilerBuilder}:
* <ul><li>R.java/Manifest.java generated by compiling the resources</li>
* <li>Any Java files generated by <code>aidl</code></li></ul>.
- *
+ *
* Therefore it looks for the following:
* <ul><li>Any modification in the resource folder</li>
* <li>Removed files from the source folder receiving generated Java files</li>
* <li>Any modification to aidl files.</li>
- *
+ *
*/
class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements
IResourceDeltaVisitor {
-
+
private enum AidlType {
UNKNOWN, INTERFACE, PARCELABLE;
}
@@ -73,7 +73,7 @@ class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements
* into R.java
*/
private boolean mCompileResources = false;
-
+
/**
* Aidl force recompilation flag. If true, we'll attempt to recompile all aidl files.
*/
@@ -84,14 +84,14 @@ class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements
/** List of .aidl files that have been removed. */
private final ArrayList<AidlData> mAidlToRemove = new ArrayList<AidlData>();
-
+
/** Manifest check/parsing flag. */
private boolean mCheckedManifestXml = false;
/** Application Package, gathered from the parsing of the manifest */
private String mJavaPackage = null;
/** minSDKVersion attribute value, gathered from the parsing of the manifest */
- private int mMinSdkVersion = AndroidManifestParser.INVALID_MIN_SDK;
+ private String mMinSdkVersion = null;
// Internal usage fields.
/**
@@ -126,7 +126,7 @@ class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements
public boolean getForceAidlCompile() {
return mForceAidlCompile;
}
-
+
public ArrayList<AidlData> getAidlToCompile() {
return mAidlToCompile;
}
@@ -134,7 +134,7 @@ class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements
public ArrayList<AidlData> getAidlToRemove() {
return mAidlToRemove;
}
-
+
/**
* Returns whether the manifest file was parsed/checked for error during the resource delta
* visiting.
@@ -142,7 +142,7 @@ class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements
public boolean getCheckedManifestXml() {
return mCheckedManifestXml;
}
-
+
/**
* Returns the manifest package if the manifest was checked/parsed.
* <p/>
@@ -162,16 +162,16 @@ class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements
/**
* Returns the minSDkVersion attribute from the manifest if it was checked/parsed.
* <p/>
- * This can return {@link AndroidManifestParser#INVALID_MIN_SDK} in two cases:
+ * This can return null in two cases:
* <ul>
* <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>
* <li>The manifest was parsed ({@link #getCheckedManifestXml()} returns <code>true</code>),
* but the package declaration is missing</li>
* </ul>
- * @return the minSdkVersion or {@link AndroidManifestParser#INVALID_MIN_SDK}.
+ * @return the minSdkVersion or null.
*/
- public int getMinSdkVersion() {
+ public String getMinSdkVersion() {
return mMinSdkVersion;
}
@@ -219,7 +219,7 @@ class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements
// parse the manifest for errors
AndroidManifestParser parser = BaseProjectHelper.parseManifestForError(
(IFile)resource, this);
-
+
if (parser != null) {
mJavaPackage = parser.getPackage();
mMinSdkVersion = parser.getApiLevelRequirement();
@@ -287,19 +287,19 @@ class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements
// Look for the source aidl file in all the source folders.
String aidlFileName = fileName.replaceAll(AndroidConstants.RE_JAVA_EXT,
AndroidConstants.DOT_AIDL);
-
+
for (IPath sourceFolderPath : mSourceFolders) {
// do not search in the current source folder as it is the 'gen' folder.
if (sourceFolderPath.equals(mSourceFolder.getFullPath())) {
continue;
}
-
+
IFolder sourceFolder = getFolder(sourceFolderPath);
if (sourceFolder != null) {
// go recursively, segment by segment.
- // index starts at 2 (0 is project, 1 is 'gen'
+ // index starts at 2 (0 is project, 1 is 'gen'
IFile sourceFile = findFile(sourceFolder, segments, 2, aidlFileName);
-
+
if (sourceFile != null) {
// found the source. add it to the list of files to compile
mAidlToCompile.add(new AidlData(sourceFolder, sourceFile));
@@ -331,7 +331,7 @@ class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements
if (AndroidConstants.EXT_AIDL.equalsIgnoreCase(ext)) {
// first check whether it's a regular file or a parcelable.
AidlType type = getAidlType(file);
-
+
if (type == AidlType.INTERFACE) {
if (kind == IResourceDelta.REMOVED) {
// we'll have to remove the generated file.
@@ -423,7 +423,7 @@ class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements
path.segment(1).equals(SdkConstants.FD_GEN_SOURCES);
return true;
}
-
+
// check if we are on the way to a source folder.
int count = sourceFolderPath.matchingFirstSegments(path);
if (count == path.segmentCount()) {
@@ -443,7 +443,7 @@ class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements
return false;
}
-
+
/**
* Searches for and return a file in a folder. The file is defined by its segments, and a new
* name (replacing the last segment).
@@ -482,10 +482,10 @@ class PreCompilerDeltaVisitor extends BaseDeltaVisitor implements
if (resource != null && resource.exists() && resource.getType() == IResource.FOLDER) {
return (IFolder)resource;
}
-
+
return null;
}
-
+
/**
* Returns the type of the aidl file. Aidl files can either declare interfaces, or declare
* parcelables. This method will attempt to parse the file and return the type. If the type
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 aad1812..b834bcf 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
@@ -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.wizards.actions.AvdManagerAction;
import com.android.prefs.AndroidLocation.AndroidLocationException;
+import com.android.sdklib.AndroidVersion;
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.NullSdkLog;
-import com.android.sdklib.SdkManager;
import com.android.sdklib.internal.avd.AvdManager;
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 debugPackageName the Android package name to debug
* @param debuggable the debuggable value of the app, or null if not set.
- * @param requiredApiVersionNumber the api version required by the app, or
- * {@link AndroidManifestParser#INVALID_MIN_SDK} if none.
+ * @param requiredApiVersionNumber the api version required by the app, or null if none.
* @param launchAction the action to perform after app sync
* @param config the launch configuration
* @param launch the launch object
*/
public void launch(final IProject project, String mode, IFile apk,
- String packageName, String debugPackageName, Boolean debuggable, int requiredApiVersionNumber,
- final IAndroidLaunchAction launchAction, final AndroidLaunchConfiguration config,
- final AndroidLaunch launch, IProgressMonitor monitor) {
+ String packageName, String debugPackageName, Boolean debuggable,
+ String requiredApiVersionNumber, final IAndroidLaunchAction launchAction,
+ final AndroidLaunchConfiguration config, final AndroidLaunch launch,
+ IProgressMonitor monitor) {
String message = String.format("Performing %1$s", launchAction.getLaunchDescription());
AdtPlugin.printToConsole(project, message);
@@ -398,17 +398,16 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
} else {
if (projectTarget.isPlatform()) { // means this can run on any device as long
// as api level is high enough
- String apiString = d.getProperty(SdkManager.PROP_VERSION_SDK);
- try {
- int apiNumber = Integer.parseInt(apiString);
- if (apiNumber >= projectTarget.getApiVersionNumber()) {
- // device is compatible with project
- compatibleRunningAvds.put(d, null);
- continue;
- }
- } catch (NumberFormatException e) {
- // do nothing, we'll consider it a non compatible device below.
+ AndroidVersion deviceVersion = Sdk.getDeviceVersion(d);
+ if (deviceVersion.canRun(projectTarget.getVersion())) {
+ // device is compatible with project
+ compatibleRunningAvds.put(d, null);
+ continue;
}
+ } else {
+ // 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;
}
@@ -544,9 +543,12 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
AvdInfo defaultAvd = null;
for (AvdInfo avd : avds) {
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 ||
- avd.getTarget().getApiVersionNumber() <
- defaultAvd.getTarget().getApiVersionNumber()) {
+ avd.getTarget().getVersion().getApiLevel() <
+ defaultAvd.getTarget().getVersion().getApiLevel()) {
defaultAvd = avd;
}
}
@@ -654,47 +656,67 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
if (device != null) {
// check the app required API level versus the target device API level
- String deviceApiVersionName = device.getProperty(IDevice.PROP_BUILD_VERSION);
- String value = device.getProperty(IDevice.PROP_BUILD_VERSION_NUMBER);
- int deviceApiVersionNumber = AndroidManifestParser.INVALID_MIN_SDK;
+ String deviceVersion = device.getProperty(IDevice.PROP_BUILD_VERSION);
+ String deviceApiLevelString = device.getProperty(IDevice.PROP_BUILD_API_LEVEL);
+ String deviceCodeName = device.getProperty(IDevice.PROP_BUILD_CODENAME);
+
+ int deviceApiLevel = -1;
try {
- deviceApiVersionNumber = Integer.parseInt(value);
+ deviceApiLevel = Integer.parseInt(deviceApiLevelString);
} 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) {
- // warn the API level requirement is not set.
+ String requiredApiString = launchInfo.getRequiredApiVersionNumber();
+ if (requiredApiString != null) {
+ int requiredApi = -1;
+ try {
+ requiredApi = Integer.parseInt(requiredApiString);
+ } catch (NumberFormatException e) {
+ // pass, we'll keep requiredApi value at -1.
+ }
+
+ if (requiredApi == -1) {
+ // this means the manifest uses a codename for minSdkVersion
+ // check that the device is using the same codename
+ if (requiredApiString.equals(deviceCodeName) == false) {
+ AdtPlugin.printErrorToConsole(launchInfo.getProject(), String.format(
+ "ERROR: Application requires a device running '%1$s'!",
+ requiredApiString));
+ return false;
+ }
+ } else {
+ // app requires a specific API level
+ if (deviceApiLevel == -1) {
+ AdtPlugin.printToConsole(launchInfo.getProject(),
+ "WARNING: Unknown device API version!");
+ } else if (deviceApiLevel < requiredApi) {
+ String msg = String.format(
+ "ERROR: Application requires API version %1$d. Device API version is %2$d (Android %3$s).",
+ requiredApi, deviceApiLevel, deviceVersion);
+ AdtPlugin.printErrorToConsole(launchInfo.getProject(), msg);
+
+ // abort the launch
+ 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 (deviceApiVersionName == null ||
- deviceApiVersionNumber == AndroidManifestParser.INVALID_MIN_SDK) {
+ 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)", deviceApiVersionNumber,
- deviceApiVersionName));
- }
- } else { // app requires a specific API level
- if (deviceApiVersionName == null ||
- deviceApiVersionNumber == AndroidManifestParser.INVALID_MIN_SDK) {
- AdtPlugin.printToConsole(launchInfo.getProject(),
- "WARNING: Unknown device API version!");
- } else if (deviceApiVersionNumber < launchInfo.getRequiredApiVersionNumber()) {
- String msg = String.format(
- "ERROR: Application requires API version %1$d. Device API version is %2$d (Android %3$s).",
- launchInfo.getRequiredApiVersionNumber(), deviceApiVersionNumber,
- deviceApiVersionName);
- AdtPlugin.printErrorToConsole(launchInfo.getProject(), msg);
-
- // abort the launch
- return false;
+ "Device API version is %1$d (Android %2$s)", deviceApiLevel,
+ deviceVersion));
}
}
+
// now checks that the device/app can be debugged (if needed)
if (device.isEmulator() == false && launchInfo.isDebugMode()) {
String debuggableDevice = device.getProperty(IDevice.PROP_DEBUGGABLE);
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/DelayedLaunchInfo.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/DelayedLaunchInfo.java
index aaa8e89..01c94fe 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/DelayedLaunchInfo.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/DelayedLaunchInfo.java
@@ -17,7 +17,6 @@
package com.android.ide.eclipse.adt.internal.launch;
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.IProject;
@@ -28,14 +27,14 @@ import org.eclipse.core.runtime.IProgressMonitor;
* application is launched.
*/
public final class DelayedLaunchInfo {
-
+
/**
- * Used to indicate behavior when Android app already exists
+ * Used to indicate behavior when Android app already exists
*/
enum InstallRetryMode {
- NEVER, ALWAYS, PROMPT;
+ NEVER, ALWAYS, PROMPT;
}
-
+
/** The device on which to launch the app */
private IDevice mDevice = null;
@@ -44,22 +43,21 @@ public final class DelayedLaunchInfo {
/** Package name */
private final String mPackageName;
-
+
/** Debug package name */
private final String mDebugPackageName;
/** IFile to the package (.apk) file */
private final IFile mPackageFile;
-
+
/** debuggable attribute of the manifest file. */
private final Boolean mDebuggable;
-
- /** Required ApiVersionNumber by the app. {@link AndroidManifestParser#INVALID_MIN_SDK} means
- * no requirements */
- private final int mRequiredApiVersionNumber;
-
+
+ /** Required Api level by the app. null means no requirements */
+ private final String mRequiredApiVersionNumber;
+
private InstallRetryMode mRetryMode = InstallRetryMode.NEVER;
-
+
/** Launch action. */
private final IAndroidLaunchAction mLaunchAction;
@@ -78,23 +76,22 @@ public final class DelayedLaunchInfo {
/** cancellation state of launch */
private boolean mCancelled = false;
- /**
- * Basic constructor with activity and package info.
- *
+ /**
+ * Basic constructor with activity and package info.
+ *
* @param project the eclipse project that corresponds to Android app
* @param packageName package name of Android app
* @param debugPackageName the package name of the Andriod app to debug
* @param launchAction action to perform after app install
* @param pack IFile to the package (.apk) file
* @param debuggable debuggable attribute of the app's manifest file.
- * @param requiredApiVersionNumber required SDK version by the app.
- * {@link AndroidManifestParser#INVALID_MIN_SDK} means no requirements.
+ * @param requiredApiVersionNumber required SDK version by the app. null means no requirements.
* @param launch the launch object
* @param monitor progress monitor for launch
*/
public DelayedLaunchInfo(IProject project, String packageName, String debugPackageName,
- IAndroidLaunchAction launchAction, IFile pack, Boolean debuggable,
- int requiredApiVersionNumber, AndroidLaunch launch, IProgressMonitor monitor) {
+ IAndroidLaunchAction launchAction, IFile pack, Boolean debuggable,
+ String requiredApiVersionNumber, AndroidLaunch launch, IProgressMonitor monitor) {
mProject = project;
mPackageName = packageName;
mDebugPackageName = debugPackageName;
@@ -112,7 +109,7 @@ public final class DelayedLaunchInfo {
public IDevice getDevice() {
return mDevice;
}
-
+
/**
* Set the device on which to launch the app
*/
@@ -153,16 +150,16 @@ public final class DelayedLaunchInfo {
}
/**
- * @return true if Android app is marked as debuggable in its manifest
+ * @return true if Android app is marked as debuggable in its manifest
*/
public Boolean getDebuggable() {
return mDebuggable;
}
/**
- * @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;
}
@@ -195,7 +192,7 @@ public final class DelayedLaunchInfo {
}
/**
- * @return the launch progress monitor
+ * @return the launch progress monitor
*/
public IProgressMonitor getMonitor() {
return mMonitor;
@@ -230,7 +227,7 @@ public final class DelayedLaunchInfo {
}
/**
- * Set if launch has been cancelled
+ * Set if launch has been cancelled
*/
public void setCancelled(boolean cancelled) {
this.mCancelled = cancelled;
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 d2fe5ae..8b61e27 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
@@ -27,6 +27,7 @@ import com.android.ddmuilib.TableHelper;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.internal.sdk.Sdk;
import com.android.ide.eclipse.ddms.DdmsPlugin;
+import com.android.sdklib.AndroidVersion;
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.internal.avd.AvdManager.AvdInfo;
import com.android.sdkuilib.internal.widgets.AvdSelector;
@@ -131,26 +132,19 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener
case 2:
// check for compatibility.
if (device.isEmulator() == false) { // physical device
- // get the api level of the device
- try {
- String apiValue = device.getProperty(
- IDevice.PROP_BUILD_VERSION_NUMBER);
- if (apiValue != null) {
- int api = Integer.parseInt(apiValue);
- if (api >= mProjectTarget.getApiVersionNumber()) {
- // if the project is compiling against an add-on, the optional
- // API may be missing from the device.
- return mProjectTarget.isPlatform() ?
- mMatchImage : mWarningImage;
- } else {
- return mNoMatchImage;
- }
- } else {
- return mWarningImage;
+ // get the version of the device
+ AndroidVersion deviceVersion = Sdk.getDeviceVersion(device);
+ if (deviceVersion == null) {
+ return mWarningImage;
+ } else {
+ if (deviceVersion.canRun(mProjectTarget.getVersion()) == false) {
+ return mNoMatchImage;
}
- } catch (NumberFormatException e) {
- // lets consider the device non compatible
- return mNoMatchImage;
+
+ // if the project is compiling against an add-on,
+ // the optional API may be missing from the device.
+ return mProjectTarget.isPlatform() ?
+ mMatchImage : mWarningImage;
}
} else {
// get the AvdInfo
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidManifestParser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidManifestParser.java
index 3deea23..d5fd4e7 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidManifestParser.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/AndroidManifestParser.java
@@ -51,7 +51,7 @@ public class AndroidManifestParser {
private final static String ATTRIBUTE_NAME = "name"; //$NON-NLS-1$
private final static String ATTRIBUTE_PROCESS = "process"; //$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_EXPORTED = "exported"; //$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 CATEGORY_LAUNCHER = "android.intent.category.LAUNCHER"; //$NON-NLS-1$
- public final static int INVALID_MIN_SDK = -1;
-
/**
* Instrumentation info obtained from manifest
*/
@@ -179,9 +177,8 @@ public class AndroidManifestParser {
private Set<String> mProcesses = null;
/** debuggable attribute value. If null, the attribute is not present. */
private Boolean mDebuggable = null;
- /** API level requirement. if {@link AndroidManifestParser#INVALID_MIN_SDK}
- * the attribute was not present. */
- private int mApiLevelRequirement = INVALID_MIN_SDK;
+ /** API level requirement. if null the attribute was not present. */
+ private String mApiLevelRequirement = null;
/** List of all instrumentations declared by the manifest */
private final ArrayList<Instrumentation> mInstrumentations =
new ArrayList<Instrumentation>();
@@ -258,10 +255,9 @@ public class AndroidManifestParser {
}
/**
- * Returns the <code>minSdkVersion</code> attribute, or
- * {@link AndroidManifestParser#INVALID_MIN_SDK} if it's not set.
+ * Returns the <code>minSdkVersion</code> attribute, or null if it's not set.
*/
- int getApiLevelRequirement() {
+ String getApiLevelRequirement() {
return mApiLevelRequirement;
}
@@ -331,16 +327,8 @@ public class AndroidManifestParser {
mValidLevel++;
} else if (NODE_USES_SDK.equals(localName)) {
- value = getAttributeValue(attributes, ATTRIBUTE_MIN_SDK_VERSION,
- true /* hasNamespace */);
-
- if (value != null) {
- try {
- mApiLevelRequirement = Integer.parseInt(value);
- } catch (NumberFormatException e) {
- handleError(e, -1 /* lineNumber */);
- }
- }
+ mApiLevelRequirement = getAttributeValue(attributes,
+ ATTRIBUTE_MIN_SDK_VERSION, true /* hasNamespace */);
} else if (NODE_INSTRUMENTATION.equals(localName)) {
processInstrumentationNode(attributes);
}
@@ -636,7 +624,7 @@ public class AndroidManifestParser {
private final Activity mLauncherActivity;
private final String[] mProcesses;
private final Boolean mDebuggable;
- private final int mApiLevelRequirement;
+ private final String mApiLevelRequirement;
private final Instrumentation[] mInstrumentations;
private final String[] mLibraries;
@@ -904,10 +892,9 @@ public class AndroidManifestParser {
}
/**
- * Returns the <code>minSdkVersion</code> attribute, or {@link #INVALID_MIN_SDK}
- * if it's not set.
+ * Returns the <code>minSdkVersion</code> attribute, or null if it's not set.
*/
- public int getApiLevelRequirement() {
+ public String getApiLevelRequirement() {
return mApiLevelRequirement;
}
@@ -939,13 +926,13 @@ public class AndroidManifestParser {
* @param launcherActivity the launcher activity parser from the manifest.
* @param processes the list of custom processes declared in the manifest.
* @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 libraries the list of libraries in use parsed from the manifest.
*/
private AndroidManifestParser(String javaPackage, Activity[] activities,
Activity launcherActivity, String[] processes, Boolean debuggable,
- int apiLevelRequirement, Instrumentation[] instrumentations, String[] libraries) {
+ String apiLevelRequirement, Instrumentation[] instrumentations, String[] libraries) {
mJavaPackage = javaPackage;
mActivities = activities;
mLauncherActivity = launcherActivity;
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetParser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetParser.java
index 5c468ec..a499137 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetParser.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidTargetParser.java
@@ -66,10 +66,10 @@ import javax.management.InvalidAttributeValueException;
* <li>Resource ID from <code>android.R</code></li>
* <li>The list of permissions values from <code>android.Manifest$permission</code></li>
* <li></li>
- * </ul>
+ * </ul>
*/
public final class AndroidTargetParser {
-
+
private static final String TAG = "Framework Resource Parser";
private final IAndroidTarget mAndroidTarget;
@@ -79,11 +79,11 @@ public final class AndroidTargetParser {
public AndroidTargetParser(IAndroidTarget platformTarget) {
mAndroidTarget = platformTarget;
}
-
+
/**
* Parses the framework, collects all interesting information and stores them in the
* {@link IAndroidTarget} given to the constructor.
- *
+ *
* @param monitor A progress monitor. Can be null. Caller is responsible for calling done.
* @return True if the SDK path was valid and parsing has been attempted.
*/
@@ -92,7 +92,7 @@ public final class AndroidTargetParser {
SubMonitor progress = SubMonitor.convert(monitor,
String.format("Parsing SDK %1$s", mAndroidTarget.getName()),
14);
-
+
AndroidTargetData targetData = new AndroidTargetData(mAndroidTarget);
// load DX.
@@ -103,22 +103,22 @@ public final class AndroidTargetParser {
String.format("dx.jar loading failed for target '%1$s'",
mAndroidTarget.getFullName()));
}
-
+
// we have loaded dx.
targetData.setDexWrapper(dexWrapper);
progress.worked(1);
-
+
// parse the rest of the data.
AndroidJarLoader classLoader =
new AndroidJarLoader(mAndroidTarget.getPath(IAndroidTarget.ANDROID_JAR));
-
+
preload(classLoader, progress.newChild(40, SubMonitor.SUPPRESS_NONE));
-
+
if (progress.isCanceled()) {
return Status.CANCEL_STATUS;
}
-
+
// get the resource Ids.
progress.subTask("Resource IDs");
IResourceRepository frameworkRepository = collectResourceIds(classLoader);
@@ -172,7 +172,7 @@ public final class AndroidTargetParser {
progress.subTask("Widgets and layouts");
collectLayoutClasses(classLoader, attrsXmlParser, mainList, groupList,
progress.newChild(1));
-
+
if (progress.isCanceled()) {
return Status.CANCEL_STATUS;
}
@@ -180,7 +180,7 @@ public final class AndroidTargetParser {
ViewClassInfo[] layoutViewsInfo = mainList.toArray(new ViewClassInfo[mainList.size()]);
ViewClassInfo[] layoutGroupsInfo = groupList.toArray(
new ViewClassInfo[groupList.size()]);
-
+
// collect the preferences classes.
mainList.clear();
groupList.clear();
@@ -203,17 +203,17 @@ public final class AndroidTargetParser {
Map<String, Map<String, Integer>> enumValueMap = attrsXmlParser.getEnumFlagValues();
Map<String, DeclareStyleableInfo> xmlAppWidgetMap = null;
- if (mAndroidTarget.getApiVersionNumber() >= 3) {
+ if (mAndroidTarget.getVersion().getApiLevel() >= 3) {
xmlAppWidgetMap = collectAppWidgetDefinitions(attrsXmlParser);
}
if (progress.isCanceled()) {
return Status.CANCEL_STATUS;
}
-
+
// From the information that was collected, create the pieces that will be put in
// the PlatformData object.
- AndroidManifestDescriptors manifestDescriptors = new AndroidManifestDescriptors();
+ AndroidManifestDescriptors manifestDescriptors = new AndroidManifestDescriptors();
manifestDescriptors.updateDescriptors(manifestMap);
progress.worked(1);
@@ -244,16 +244,16 @@ public final class AndroidTargetParser {
preferencesInfo,
preferenceGroupsInfo);
progress.worked(1);
-
+
// load the framework resources.
ProjectResources resources = ResourceManager.getInstance().loadFrameworkResources(
mAndroidTarget);
progress.worked(1);
-
+
// now load the layout lib bridge
LayoutBridge layoutBridge = loadLayoutBridge();
progress.worked(1);
-
+
// and finally create the PlatformData with all that we loaded.
targetData.setExtraData(frameworkRepository,
manifestDescriptors,
@@ -270,7 +270,7 @@ public final class AndroidTargetParser {
mAndroidTarget.getOptionalLibraries(),
resources,
layoutBridge);
-
+
Sdk.getCurrent().setTargetData(mAndroidTarget, targetData);
return Status.OK_STATUS;
@@ -285,7 +285,7 @@ public final class AndroidTargetParser {
* Preloads all "interesting" classes from the framework SDK jar.
* <p/>
* Currently this preloads all classes from the framework jar
- *
+ *
* @param classLoader The framework SDK jar classloader
* @param monitor A progress monitor. Can be null. Caller is responsible for calling done.
*/
@@ -303,7 +303,7 @@ public final class AndroidTargetParser {
/**
* Creates an IResourceRepository for the framework resources.
- *
+ *
* @param classLoader The framework SDK jar classloader
* @return a map of the resources, or null if it failed.
*/
@@ -311,7 +311,7 @@ public final class AndroidTargetParser {
AndroidJarLoader classLoader) {
try {
Class<?> r = classLoader.loadClass(AndroidConstants.CLASS_R);
-
+
if (r != null) {
Map<ResourceType, List<ResourceItem>> map = parseRClass(r);
if (map != null) {
@@ -321,23 +321,23 @@ public final class AndroidTargetParser {
} catch (ClassNotFoundException e) {
AdtPlugin.logAndPrintError(e, TAG,
"Collect resource IDs failed, class %1$s not found in %2$s", //$NON-NLS-1$
- AndroidConstants.CLASS_R,
+ AndroidConstants.CLASS_R,
mAndroidTarget.getPath(IAndroidTarget.ANDROID_JAR));
}
-
+
return null;
}
-
+
/**
* Parse the R class and build the resource map.
- *
+ *
* @param rClass the Class object representing the Resources.
* @return a map of the resource or null
*/
private Map<ResourceType, List<ResourceItem>> parseRClass(Class<?> rClass) {
// get the sub classes.
Class<?>[] classes = rClass.getClasses();
-
+
if (classes.length > 0) {
HashMap<ResourceType, List<ResourceItem>> map =
new HashMap<ResourceType, List<ResourceItem>>();
@@ -346,30 +346,30 @@ public final class AndroidTargetParser {
for (int c = 0 ; c < classes.length ; c++) {
Class<?> subClass = classes[c];
String name = subClass.getSimpleName();
-
+
// get the matching ResourceType
ResourceType type = ResourceType.getEnum(name);
if (type != null) {
List<ResourceItem> list = new ArrayList<ResourceItem>();
map.put(type, list);
-
+
Field[] fields = subClass.getFields();
-
+
for (Field f : fields) {
list.add(new ResourceItem(f.getName()));
}
}
}
-
+
return map;
}
-
+
return null;
}
/**
* Loads, collects and returns the list of default permissions from the framework.
- *
+ *
* @param classLoader The framework SDK jar classloader
* @return a non null (but possibly empty) array containing the permission values.
*/
@@ -377,12 +377,12 @@ public final class AndroidTargetParser {
try {
Class<?> permissionClass =
classLoader.loadClass(AndroidConstants.CLASS_MANIFEST_PERMISSION);
-
+
if (permissionClass != null) {
ArrayList<String> list = new ArrayList<String>();
Field[] fields = permissionClass.getFields();
-
+
for (Field f : fields) {
int modifiers = f.getModifiers();
if (Modifier.isStatic(modifiers) && Modifier.isFinal(modifiers) &&
@@ -403,23 +403,23 @@ public final class AndroidTargetParser {
}
}
}
-
+
return list.toArray(new String[list.size()]);
}
} catch (ClassNotFoundException e) {
AdtPlugin.logAndPrintError(e, TAG,
"Collect permissions failed, class %1$s not found in %2$s", //$NON-NLS-1$
- AndroidConstants.CLASS_MANIFEST_PERMISSION,
+ AndroidConstants.CLASS_MANIFEST_PERMISSION,
mAndroidTarget.getPath(IAndroidTarget.ANDROID_JAR));
}
-
+
return new String[0];
}
-
+
/**
* Loads and collects the action and category default values from the framework.
* The values are added to the <code>actions</code> and <code>categories</code> lists.
- *
+ *
* @param activityActions the list which will receive the activity action values.
* @param broadcastActions the list which will receive the broadcast action values.
* @param serviceActions the list which will receive the service action values.
@@ -481,7 +481,7 @@ public final class AndroidTargetParser {
/**
* Collects all layout classes information from the class loader and the
* attrs.xml and sets the corresponding structures in the resource manager.
- *
+ *
* @param classLoader The framework SDK jar classloader in case we cannot get the widget from
* the platform directly
* @param attrsXmlParser The parser of the attrs.xml file
@@ -491,7 +491,7 @@ public final class AndroidTargetParser {
*/
private void collectLayoutClasses(AndroidJarLoader classLoader,
AttrsXmlParser attrsXmlParser,
- Collection<ViewClassInfo> mainList, Collection<ViewClassInfo> groupList,
+ Collection<ViewClassInfo> mainList, Collection<ViewClassInfo> groupList,
IProgressMonitor monitor) {
LayoutParamsParser ldp = null;
try {
@@ -510,7 +510,7 @@ public final class AndroidTargetParser {
ldp = new LayoutParamsParser(classLoader, attrsXmlParser);
}
ldp.parseLayoutClasses(monitor);
-
+
List<ViewClassInfo> views = ldp.getViews();
List<ViewClassInfo> groups = ldp.getGroups();
@@ -523,7 +523,7 @@ public final class AndroidTargetParser {
/**
* Collects all preferences definition information from the attrs.xml and
* sets the corresponding structures in the resource manager.
- *
+ *
* @param classLoader The framework SDK jar classloader
* @param attrsXmlParser The parser of the attrs.xml file
* @param mainList the Collection to receive the main list of {@link ViewClassInfo}.
@@ -534,13 +534,13 @@ public final class AndroidTargetParser {
AttrsXmlParser attrsXmlParser, Collection<ViewClassInfo> mainList,
Collection<ViewClassInfo> groupList, IProgressMonitor monitor) {
LayoutParamsParser ldp = new LayoutParamsParser(classLoader, attrsXmlParser);
-
+
try {
ldp.parsePreferencesClasses(monitor);
-
+
List<ViewClassInfo> prefs = ldp.getViews();
List<ViewClassInfo> groups = ldp.getGroups();
-
+
if (prefs != null && groups != null) {
mainList.addAll(prefs);
groupList.addAll(groups);
@@ -548,7 +548,7 @@ public final class AndroidTargetParser {
} catch (NoClassDefFoundError e) {
AdtPlugin.logAndPrintError(e, TAG,
"Collect preferences failed, class %1$s not found in %2$s",
- e.getMessage(),
+ e.getMessage(),
classLoader.getSource());
} catch (Throwable e) {
AdtPlugin.log(e, "Android Framework Parser: failed to collect preference classes"); //$NON-NLS-1$
@@ -559,7 +559,7 @@ public final class AndroidTargetParser {
/**
* Collects all menu definition information from the attrs.xml and returns it.
- *
+ *
* @param attrsXmlParser The parser of the attrs.xml file
*/
private Map<String, DeclareStyleableInfo> collectMenuDefinitions(
@@ -575,18 +575,18 @@ public final class AndroidTargetParser {
AdtPlugin.log(IStatus.WARNING,
"Menu declare-styleable %1$s not found in file %2$s", //$NON-NLS-1$
key, attrsXmlParser.getOsAttrsXmlPath());
- AdtPlugin.printErrorToConsole("Android Framework Parser",
+ AdtPlugin.printErrorToConsole("Android Framework Parser",
String.format("Menu declare-styleable %1$s not found in file %2$s", //$NON-NLS-1$
key, attrsXmlParser.getOsAttrsXmlPath()));
}
}
-
+
return Collections.unmodifiableMap(map2);
}
/**
* Collects all searchable definition information from the attrs.xml and returns it.
- *
+ *
* @param attrsXmlParser The parser of the attrs.xml file
*/
private Map<String, DeclareStyleableInfo> collectSearchableDefinitions(
@@ -612,7 +612,7 @@ public final class AndroidTargetParser {
/**
* Collects all appWidgetProviderInfo definition information from the attrs.xml and returns it.
- *
+ *
* @param attrsXmlParser The parser of the attrs.xml file
*/
private Map<String, DeclareStyleableInfo> collectAppWidgetDefinitions(
@@ -657,13 +657,13 @@ public final class AndroidTargetParser {
AdtPlugin.log(IStatus.ERROR, "layoutlib.jar is missing!"); //$NON-NLS-1$
} else {
URL url = f.toURL();
-
+
// create a class loader. Because this jar reference interfaces
- // that are in the editors plugin, it's important to provide
+ // that are in the editors plugin, it's important to provide
// a parent class loader.
layoutBridge.classLoader = new URLClassLoader(new URL[] { url },
this.getClass().getClassLoader());
-
+
// load the class
Class<?> clazz = layoutBridge.classLoader.loadClass(AndroidConstants.CLASS_BRIDGE);
if (clazz != null) {
@@ -676,7 +676,7 @@ public final class AndroidTargetParser {
}
}
}
-
+
if (layoutBridge.bridge == null) {
layoutBridge.status = LoadStatus.FAILED;
AdtPlugin.log(IStatus.ERROR, "Failed to load " + AndroidConstants.CLASS_BRIDGE); //$NON-NLS-1$
@@ -688,7 +688,7 @@ public final class AndroidTargetParser {
// the first version of the api did not have this method
layoutBridge.apiLevel = 1;
}
-
+
// and mark the lib as loaded.
layoutBridge.status = LoadStatus.LOADED;
}
@@ -698,7 +698,7 @@ public final class AndroidTargetParser {
// log the error.
AdtPlugin.log(t, "Failed to load the LayoutLib");
}
-
+
return layoutBridge;
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java
index 0fe592a..d6cfeae 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/Sdk.java
@@ -16,12 +16,14 @@
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.internal.project.AndroidClasspathContainerInitializer;
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.sdk.AndroidTargetData.LayoutBridge;
import com.android.prefs.AndroidLocation.AndroidLocationException;
+import com.android.sdklib.AndroidVersion;
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.ISdkLog;
import com.android.sdklib.SdkConstants;
@@ -394,6 +396,21 @@ public class Sdk implements IProjectListener {
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) {
mManager = manager;
mAvdManager = avdManager;
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectCreationPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectCreationPage.java
index 95b6ea1..5067111 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectCreationPage.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectCreationPage.java
@@ -840,25 +840,21 @@ public class NewProjectCreationPage extends WizardPage {
return;
}
- try {
- int version = Integer.parseInt(mInfo.getMinSdkVersion());
-
- // 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
- // it if it's already at the right version.
- IAndroidTarget curr_target = mInfo.getSdkTarget();
- if (curr_target != null && curr_target.getApiVersionNumber() == version) {
- return;
- }
+ String minSdkVersion = mInfo.getMinSdkVersion();
- for (IAndroidTarget target : mSdkTargetSelector.getTargets()) {
- if (target.getApiVersionNumber() == version) {
- mSdkTargetSelector.setSelection(target);
- break;
- }
+ // 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
+ // it if it's already at the right version.
+ IAndroidTarget curr_target = mInfo.getSdkTarget();
+ if (curr_target != null && curr_target.getVersion().equals(minSdkVersion)) {
+ return;
+ }
+
+ for (IAndroidTarget target : mSdkTargetSelector.getTargets()) {
+ if (target.getVersion().equals(minSdkVersion)) {
+ mSdkTargetSelector.setSelection(target);
+ break;
}
- } catch (NumberFormatException e) {
- // ignore
}
}
@@ -873,7 +869,7 @@ public class NewProjectCreationPage extends WizardPage {
if (target != null) {
mInternalMinSdkVersionUpdate = true;
- mMinSdkVersionField.setText(Integer.toString(target.getApiVersionNumber()));
+ mMinSdkVersionField.setText(target.getVersion().getApiString());
mInternalMinSdkVersionUpdate = false;
}
}
@@ -932,7 +928,7 @@ public class NewProjectCreationPage extends WizardPage {
String packageName = null;
Activity activity = null;
String activityName = null;
- int minSdkVersion = AndroidManifestParser.INVALID_MIN_SDK;
+ String minSdkVersion = null;
try {
packageName = manifestData.getPackage();
minSdkVersion = manifestData.getApiLevelRequirement();
@@ -1033,17 +1029,13 @@ public class NewProjectCreationPage extends WizardPage {
}
}
- if (!foundTarget && minSdkVersion != AndroidManifestParser.INVALID_MIN_SDK) {
- try {
- for (IAndroidTarget target : mSdkTargetSelector.getTargets()) {
- if (target.getApiVersionNumber() == minSdkVersion) {
- mSdkTargetSelector.setSelection(target);
- foundTarget = true;
- break;
- }
+ if (!foundTarget && minSdkVersion != null) {
+ for (IAndroidTarget target : mSdkTargetSelector.getTargets()) {
+ if (target.getVersion().equals(minSdkVersion)) {
+ mSdkTargetSelector.setSelection(target);
+ foundTarget = true;
+ break;
}
- } catch(NumberFormatException e) {
- // ignore
}
}
@@ -1059,9 +1051,9 @@ public class NewProjectCreationPage extends WizardPage {
if (!foundTarget) {
mInternalMinSdkVersionUpdate = true;
- mMinSdkVersionField.setText(
- minSdkVersion == AndroidManifestParser.INVALID_MIN_SDK ? "" //$NON-NLS-1$
- : Integer.toString(minSdkVersion));
+ if (minSdkVersion != null) {
+ mMinSdkVersionField.setText(minSdkVersion);
+ }
mInternalMinSdkVersionUpdate = false;
}
}
@@ -1269,21 +1261,10 @@ public class NewProjectCreationPage extends WizardPage {
return MSG_NONE;
}
- int version = AndroidManifestParser.INVALID_MIN_SDK;
- try {
- // 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) {
+ if (mInfo.getSdkTarget() != null &&
+ mInfo.getSdkTarget().getVersion().equals(mInfo.getMinSdkVersion()) == false) {
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;
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewTestProjectCreationPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewTestProjectCreationPage.java
index 22c2749..94fd99d 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewTestProjectCreationPage.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewTestProjectCreationPage.java
@@ -821,7 +821,7 @@ public class NewTestProjectCreationPage extends WizardPage {
if (manifestData != null) {
String appName = String.format("%1$sTest", project.getName());
String packageName = manifestData.getPackage();
- int minSdkVersion = manifestData.getApiLevelRequirement();
+ String minSdkVersion = manifestData.getApiLevelRequirement();
IAndroidTarget sdkTarget = null;
if (Sdk.getCurrent() != null) {
sdkTarget = Sdk.getCurrent().getTarget(project);
@@ -859,9 +859,9 @@ public class NewTestProjectCreationPage extends WizardPage {
if (!mMinSdkVersionModifiedByUser) {
mInternalMinSdkVersionUpdate = true;
- mMinSdkVersionField.setText(
- minSdkVersion != AndroidManifestParser.INVALID_MIN_SDK ?
- Integer.toString(minSdkVersion) : ""); //$NON-NLS-1$
+ if (minSdkVersion != null) {
+ mMinSdkVersionField.setText(minSdkVersion);
+ }
if (sdkTarget == null) {
updateSdkSelectorToMatchMinSdkVersion();
}
@@ -1052,22 +1052,18 @@ public class NewTestProjectCreationPage extends WizardPage {
* that matches.
*/
private void updateSdkSelectorToMatchMinSdkVersion() {
- try {
- int version = Integer.parseInt(mInfo.getMinSdkVersion());
+ String minSdkVersion = mInfo.getMinSdkVersion();
- IAndroidTarget curr_target = mInfo.getSdkTarget();
- if (curr_target != null && curr_target.getApiVersionNumber() == version) {
- return;
- }
+ IAndroidTarget curr_target = mInfo.getSdkTarget();
+ if (curr_target != null && curr_target.getVersion().equals(minSdkVersion)) {
+ return;
+ }
- for (IAndroidTarget target : mSdkTargetSelector.getTargets()) {
- if (target.getApiVersionNumber() == version) {
- mSdkTargetSelector.setSelection(target);
- return;
- }
+ for (IAndroidTarget target : mSdkTargetSelector.getTargets()) {
+ if (target.getVersion().equals(minSdkVersion)) {
+ mSdkTargetSelector.setSelection(target);
+ return;
}
- } catch (NumberFormatException e) {
- // ignore
}
}
@@ -1086,7 +1082,7 @@ public class NewTestProjectCreationPage extends WizardPage {
if (target != null) {
mInternalMinSdkVersionUpdate = true;
- mMinSdkVersionField.setText(Integer.toString(target.getApiVersionNumber()));
+ mMinSdkVersionField.setText(target.getVersion().getApiString());
mInternalMinSdkVersionUpdate = false;
}
@@ -1261,21 +1257,10 @@ public class NewTestProjectCreationPage extends WizardPage {
return MSG_NONE;
}
- int version = AndroidManifestParser.INVALID_MIN_SDK;
- try {
- // 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) {
+ if (mInfo.getSdkTarget() != null &&
+ mInfo.getSdkTarget().getVersion().equals(mInfo.getMinSdkVersion()) == false) {
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;
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java
index 8c242c0..4edfb77 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java
@@ -87,10 +87,10 @@ class NewXmlFileCreationPage extends WizardPage {
private final String mDefaultAttrs;
private final String mDefaultRoot;
private final int mTargetApiLevel;
-
+
public TypeInfo(String uiName,
- String tooltip,
- ResourceFolderType resFolderType,
+ String tooltip,
+ ResourceFolderType resFolderType,
Object rootSeed,
String defaultRoot,
String xmlns,
@@ -110,12 +110,12 @@ class NewXmlFileCreationPage extends WizardPage {
String getUiName() {
return mUiName;
}
-
- /** Returns the tooltip for the resource type. Can be null. */
+
+ /** Returns the tooltip for the resource type. Can be null. */
String getTooltip() {
return mTooltip;
}
-
+
/**
* Returns the name of the {@link ResourceFolderType}.
* Never null but not necessarily unique,
@@ -124,7 +124,7 @@ class NewXmlFileCreationPage extends WizardPage {
String getResFolderName() {
return mResFolderType.getName();
}
-
+
/**
* Returns the matching {@link ResourceFolderType}.
* Never null but not necessarily unique,
@@ -138,16 +138,16 @@ class NewXmlFileCreationPage extends WizardPage {
void setWidget(Button widget) {
mWidget = widget;
}
-
+
/** Returns the radio button associate with the resource type. Can be null. */
Button getWidget() {
return mWidget;
}
-
+
/**
* Returns the seed used to fill the root element values.
* The seed might be either a String, a String array, an {@link ElementDescriptor},
- * a {@link DocumentDescriptor} or null.
+ * a {@link DocumentDescriptor} or null.
*/
Object getRootSeed() {
return mRootSeed;
@@ -278,7 +278,7 @@ class NewXmlFileCreationPage extends WizardPage {
private static final String RES_FOLDER_ABS = AndroidConstants.WS_RESOURCES + AndroidConstants.WS_SEP;
/** Relative destination folder root, e.g. "res/" */
private static final String RES_FOLDER_REL = SdkConstants.FD_RESOURCES + AndroidConstants.WS_SEP;
-
+
private IProject mProject;
private Text mProjectTextField;
private Button mProjectBrowseButton;
@@ -297,7 +297,7 @@ class NewXmlFileCreationPage extends WizardPage {
private TypeInfo mCurrentTypeInfo;
// --- UI creation ---
-
+
/**
* Constructs a new {@link NewXmlFileCreationPage}.
* <p/>
@@ -314,9 +314,9 @@ class NewXmlFileCreationPage extends WizardPage {
/**
* Called by the parent Wizard to create the UI for this Wizard Page.
- *
+ *
* {@inheritDoc}
- *
+ *
* @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
*/
public void createControl(Composite parent) {
@@ -347,7 +347,7 @@ class NewXmlFileCreationPage extends WizardPage {
installTargetChangeListener();
validatePage();
}
-
+
private void installTargetChangeListener() {
mSdkTargetChangeListener = new ITargetChangeListener() {
public void onProjectTargetChange(IProject changedProject) {
@@ -364,18 +364,18 @@ class NewXmlFileCreationPage extends WizardPage {
}
}
};
-
+
AdtPlugin.getDefault().addTargetListener(mSdkTargetChangeListener);
}
@Override
public void dispose() {
-
+
if (mSdkTargetChangeListener != null) {
AdtPlugin.getDefault().removeTargetListener(mSdkTargetChangeListener);
mSdkTargetChangeListener = null;
}
-
+
super.dispose();
}
@@ -399,7 +399,7 @@ class NewXmlFileCreationPage extends WizardPage {
public String getWsFolderPath() {
return mWsFolderPathTextField == null ? "" : mWsFolderPathTextField.getText(); //$NON-NLS-1$
}
-
+
/**
* Returns an {@link IFile} on the destination file.
@@ -426,7 +426,7 @@ class NewXmlFileCreationPage extends WizardPage {
/**
* Returns the {@link TypeInfo} for the currently selected type radio button.
* Returns null if no radio button is selected.
- *
+ *
* @return A {@link TypeInfo} or null.
*/
public TypeInfo getSelectedType() {
@@ -439,10 +439,10 @@ class NewXmlFileCreationPage extends WizardPage {
}
return type;
}
-
+
/**
* Returns the selected root element string, if any.
- *
+ *
* @return The selected root element string or null.
*/
public String getRootElement() {
@@ -457,7 +457,7 @@ class NewXmlFileCreationPage extends WizardPage {
/**
* Helper method to create a new GridData with an horizontal span.
- *
+ *
* @param horizSpan The number of cells for the horizontal span.
* @return A new GridData with the horizontal span.
*/
@@ -469,7 +469,7 @@ class NewXmlFileCreationPage extends WizardPage {
/**
* Helper method to create a new GridData with an horizontal span and a style.
- *
+ *
* @param horizSpan The number of cells for the horizontal span.
* @param style The style, e.g. {@link GridData#FILL_HORIZONTAL}
* @return A new GridData with the horizontal span and the style.
@@ -482,7 +482,7 @@ class NewXmlFileCreationPage extends WizardPage {
/**
* Helper method that creates an empty cell in the parent composite.
- *
+ *
* @param parent The parent composite.
*/
private void emptyCell(Composite parent) {
@@ -491,7 +491,7 @@ class NewXmlFileCreationPage extends WizardPage {
/**
* Pads the parent with empty cells to match the number of columns of the parent grid.
- *
+ *
* @param parent A grid layout with NUM_COL columns
* @param col The current number of columns used.
* @return 0, the new number of columns used, for convenience.
@@ -511,7 +511,7 @@ class NewXmlFileCreationPage extends WizardPage {
*/
private void createProjectGroup(Composite parent) {
int col = 0;
-
+
// project name
String tooltip = "The Android Project where the new resource file will be created.";
Label label = new Label(parent, SWT.NONE);
@@ -542,7 +542,7 @@ class NewXmlFileCreationPage extends WizardPage {
++col;
col = padWithEmptyCells(parent, col);
-
+
// file name
tooltip = "The name of the resource file to create.";
label = new Label(parent, SWT.NONE);
@@ -572,7 +572,7 @@ class NewXmlFileCreationPage extends WizardPage {
// separator
Label label = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL);
label.setLayoutData(newGridData(NUM_COL, GridData.GRAB_HORIZONTAL));
-
+
// label before type radios
label = new Label(parent, SWT.NONE);
label.setText("What type of resource would you like to create?");
@@ -584,7 +584,7 @@ class NewXmlFileCreationPage extends WizardPage {
padWithEmptyCells(parent, 2);
grid.setLayout(new GridLayout(NUM_COL, true /*makeColumnsEqualWidth*/));
-
+
SelectionListener radioListener = new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
@@ -594,7 +594,7 @@ class NewXmlFileCreationPage extends WizardPage {
}
}
};
-
+
int n = sTypes.length;
int num_lines = (n + NUM_COL/2) / NUM_COL;
for (int line = 0, k = 0; line < num_lines; line++) {
@@ -627,7 +627,7 @@ class NewXmlFileCreationPage extends WizardPage {
mConfigSelector.setLayoutData(gd);
mConfigSelector.setOnChangeListener(new onConfigSelectorUpdated());
emptyCell(parent);
-
+
// folder name
String tooltip = "The folder where the file will be generated, relative to the project.";
label = new Label(parent, SWT.NONE);
@@ -669,7 +669,7 @@ class NewXmlFileCreationPage extends WizardPage {
mRootElementCombo.select(0);
mRootElementCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
mRootElementCombo.setToolTipText(tooltip);
-
+
padWithEmptyCells(parent, 2);
}
@@ -683,7 +683,7 @@ class NewXmlFileCreationPage extends WizardPage {
* <li>The current folder, valid if it's a folder under /res</li>
* <li>An existing filename, in which case the user will be asked whether to override it.</li>
* <ul>
- *
+ *
* @param selection The selection when the wizard was initiated.
*/
private void initializeFromSelection(IStructuredSelection selection) {
@@ -702,7 +702,7 @@ class NewXmlFileCreationPage extends WizardPage {
if (element instanceof IAdaptable) {
IResource res = (IResource) ((IAdaptable) element).getAdapter(IResource.class);
IProject project = res != null ? res.getProject() : null;
-
+
// Is this an Android project?
try {
if (project == null || !project.hasNature(AndroidConstants.NATURE)) {
@@ -712,18 +712,18 @@ class NewXmlFileCreationPage extends WizardPage {
// checking the nature failed, ignore this resource
continue;
}
-
+
int score = 1; // we have a valid project at least
IPath wsFolderPath = null;
String fileName = null;
if (res.getType() == IResource.FOLDER) {
- wsFolderPath = res.getProjectRelativePath();
+ wsFolderPath = res.getProjectRelativePath();
} else if (res.getType() == IResource.FILE) {
fileName = res.getName();
wsFolderPath = res.getParent().getProjectRelativePath();
}
-
+
// Disregard this folder selection if it doesn't point to /res/something
if (wsFolderPath != null &&
wsFolderPath.segmentCount() > 1 &&
@@ -735,7 +735,7 @@ class NewXmlFileCreationPage extends WizardPage {
}
score += fileName != null ? 4 : 0;
-
+
if (score > targetScore) {
targetScore = score;
targetProject = project;
@@ -744,7 +744,7 @@ class NewXmlFileCreationPage extends WizardPage {
}
}
}
-
+
// Now set the UI accordingly
if (targetScore > 0) {
mProject = targetProject;
@@ -764,7 +764,7 @@ class NewXmlFileCreationPage extends WizardPage {
if (roots.size() > 0) {
roots.clear();
}
-
+
// depending of the type of the seed, initialize the root in different ways
Object rootSeed = type.getRootSeed();
@@ -783,7 +783,7 @@ class NewXmlFileCreationPage extends WizardPage {
// Note: if project is null, the root list will be empty since it has been
// cleared above.
-
+
// get the AndroidTargetData from the project
IAndroidTarget target = null;
AndroidTargetData data = null;
@@ -793,7 +793,7 @@ class NewXmlFileCreationPage extends WizardPage {
// A project should have a target. The target can be missing if the project
// is an old project for which a target hasn't been affected or if the
// target no longer exists in this SDK. Simply log the error and dismiss.
-
+
AdtPlugin.log(IStatus.INFO,
"NewXmlFile wizard: no platform target for project %s", //$NON-NLS-1$
mProject.getName());
@@ -807,14 +807,14 @@ class NewXmlFileCreationPage extends WizardPage {
// loaded we can end up in a weird case where we have a target but it
// doesn't have any data yet.
// Lets log a warning and silently ignore this root.
-
+
AdtPlugin.log(IStatus.INFO,
"NewXmlFile wizard: no data for target %s, project %s", //$NON-NLS-1$
target.getName(), mProject.getName());
continue;
}
}
-
+
IDescriptorProvider provider = data.getDescriptorProvider((Integer)rootSeed);
ElementDescriptor descriptor = provider.getDescriptor();
if (descriptor != null) {
@@ -842,22 +842,22 @@ class NewXmlFileCreationPage extends WizardPage {
roots.add(xmlName);
}
}
-
+
visited.add(desc);
-
+
for (ElementDescriptor child : desc.getChildren()) {
if (!visited.contains(child)) {
initRootElementDescriptor(roots, child, visited);
}
}
}
-
+
/**
* Callback called when the user edits the project text field.
*/
private void onProjectFieldUpdated() {
String project = mProjectTextField.getText();
-
+
// Is this a valid project?
IJavaProject[] projects = mProjectChooserHelper.getAndroidProjects(null /*javaModel*/);
IProject found = null;
@@ -896,15 +896,15 @@ class NewXmlFileCreationPage extends WizardPage {
// enable types based on new API level
enableTypesBasedOnApi();
-
+
// update the Type with the new descriptors.
initializeRootValues();
-
+
// update the combo
updateRootCombo(getSelectedType());
-
+
validatePage();
- }
+ }
/**
* Callback called when the Folder text field is changed, either programmatically
@@ -929,7 +929,7 @@ class NewXmlFileCreationPage extends WizardPage {
// We get "res/foo" from selections relative to the project when we want a "/res/foo" path.
if (wsFolderPath.startsWith(RES_FOLDER_REL)) {
wsFolderPath = RES_FOLDER_ABS + wsFolderPath.substring(RES_FOLDER_REL.length());
-
+
mInternalWsFolderPathUpdate = true;
mWsFolderPathTextField.setText(wsFolderPath);
mInternalWsFolderPathUpdate = false;
@@ -937,7 +937,7 @@ class NewXmlFileCreationPage extends WizardPage {
if (wsFolderPath.startsWith(RES_FOLDER_ABS)) {
wsFolderPath = wsFolderPath.substring(RES_FOLDER_ABS.length());
-
+
int pos = wsFolderPath.indexOf(AndroidConstants.WS_SEP_CHAR);
if (pos >= 0) {
wsFolderPath = wsFolderPath.substring(0, pos);
@@ -985,7 +985,7 @@ class NewXmlFileCreationPage extends WizardPage {
/**
* Callback called when one of the type radio button is changed.
- *
+ *
* @param typeWidget The type radio button that changed.
*/
private void onRadioTypeUpdated(Button typeWidget) {
@@ -1003,13 +1003,13 @@ class NewXmlFileCreationPage extends WizardPage {
break;
}
}
-
+
if (type == null) {
return;
}
// update the combo
-
+
updateRootCombo(type);
// update the folder path
@@ -1022,7 +1022,7 @@ class NewXmlFileCreationPage extends WizardPage {
if (qual == null) {
// The configuration is valid. Reformat the folder path using the canonical
// value from the configuration.
-
+
newPath = RES_FOLDER_ABS + mTempConfig.getFolderName(type.getResFolderType());
} else {
// The configuration is invalid. We still update the path but this time
@@ -1049,7 +1049,7 @@ class NewXmlFileCreationPage extends WizardPage {
* Helper method that fills the values of the "root element" combo box based
* on the currently selected type radio button. Also disables the combo is there's
* only one choice. Always select the first root element for the given type.
- *
+ *
* @param type The currently selected {@link TypeInfo}. Cannot be null.
*/
private void updateRootCombo(TypeInfo type) {
@@ -1059,14 +1059,14 @@ class NewXmlFileCreationPage extends WizardPage {
if (type != null) {
// get the list of roots. The list can be empty but not null.
ArrayList<String> roots = type.getRoots();
-
+
// enable the combo if there's more than one choice
mRootElementCombo.setEnabled(roots != null && roots.size() > 1);
-
+
for (String root : roots) {
mRootElementCombo.add(root);
}
-
+
int index = 0; // default is to select the first one
String defaultRoot = type.getDefaultRoot();
if (defaultRoot != null) {
@@ -1086,16 +1086,16 @@ class NewXmlFileCreationPage extends WizardPage {
}
TypeInfo type = getSelectedType();
-
+
if (type != null) {
mConfigSelector.getConfiguration(mTempConfig);
StringBuffer sb = new StringBuffer(RES_FOLDER_ABS);
sb.append(mTempConfig.getFolderName(type.getResFolderType()));
-
+
mInternalWsFolderPathUpdate = true;
mWsFolderPathTextField.setText(sb.toString());
mInternalWsFolderPathUpdate = false;
-
+
validatePage();
}
}
@@ -1103,7 +1103,7 @@ class NewXmlFileCreationPage extends WizardPage {
/**
* Helper method to select on of the type radio buttons.
- *
+ *
* @param type The TypeInfo matching the radio button to selected or null to deselect them all.
*/
private void selectType(TypeInfo type) {
@@ -1130,9 +1130,9 @@ class NewXmlFileCreationPage extends WizardPage {
IAndroidTarget target = mProject != null ? Sdk.getCurrent().getTarget(mProject) : null;
int currentApiLevel = 1;
if (target != null) {
- currentApiLevel = target.getApiVersionNumber();
+ currentApiLevel = target.getVersion().getApiLevel();
}
-
+
for (TypeInfo type : sTypes) {
type.getWidget().setEnabled(type.getTargetApiLevel() <= currentApiLevel);
}
@@ -1175,7 +1175,7 @@ class NewXmlFileCreationPage extends WizardPage {
IAndroidTarget target = Sdk.getCurrent().getTarget(mProject);
int currentApiLevel = 1;
if (target != null) {
- currentApiLevel = target.getApiVersionNumber();
+ currentApiLevel = target.getVersion().getApiLevel();
}
TypeInfo type = getSelectedType();
diff --git a/sdkmanager/app/src/com/android/sdkmanager/Main.java b/sdkmanager/app/src/com/android/sdkmanager/Main.java
index c95fa04..aab8066 100644
--- a/sdkmanager/app/src/com/android/sdkmanager/Main.java
+++ b/sdkmanager/app/src/com/android/sdkmanager/Main.java
@@ -416,7 +416,7 @@ class Main {
mSdkLog.printf(" Name: %s\n", target.getName());
if (target.isPlatform()) {
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());
} else {
mSdkLog.printf(" Type: Add-On\n");
@@ -426,7 +426,7 @@ class Main {
mSdkLog.printf(" Description: %s\n", target.getDescription());
}
mSdkLog.printf(" Based on Android %s (API level %d)\n",
- target.getApiVersionName(), target.getApiVersionNumber());
+ target.getVersionName(), target.getVersion().getApiString());
// display the optional libraries.
IOptionalLibrary[] libraries = target.getOptionalLibraries();
@@ -501,13 +501,13 @@ class Main {
// get the target of the AVD
IAndroidTarget target = info.getTarget();
if (target.isPlatform()) {
- mSdkLog.printf(" Target: %s (API level %d)\n", target.getName(),
- target.getApiVersionNumber());
+ mSdkLog.printf(" Target: %s (API level %s)\n", target.getName(),
+ target.getVersion().getApiString());
} else {
mSdkLog.printf(" Target: %s (%s)\n", target.getName(), target
.getVendor());
- mSdkLog.printf(" Based on Android %s (API level %d)\n", target
- .getApiVersionName(), target.getApiVersionNumber());
+ mSdkLog.printf(" Based on Android %s (API level %s)\n",
+ target.getVersionName(), target.getVersion().getApiString());
}
// display some extra values.
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java
index 3ac0d1a..a4b50ed 100644
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java
@@ -137,14 +137,13 @@ final class AddOnTarget implements IAndroidTarget {
return mDescription;
}
- public String getApiVersionName() {
+ public AndroidVersion getVersion() {
// this is always defined by the base platform
- return mBasePlatform.getApiVersionName();
+ return mBasePlatform.getVersion();
}
- public int getApiVersionNumber() {
- // this is always defined by the base platform
- return mBasePlatform.getApiVersionNumber();
+ public String getVersionName() {
+ return mBasePlatform.getVersionName();
}
public int getRevision() {
@@ -182,7 +181,7 @@ final class AddOnTarget implements IAndroidTarget {
return sampleLoc.getAbsolutePath();
}
}
- // INTENT FALL-THROUGH
+ // INTENDED FALL-THROUGH
default :
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
// the receiver is compatible.
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
// number greater or equal (ie target is a newer version of this add-on).
if (target.isPlatform() == false) {
return (mVendor.equals(target.getVendor()) && mName.equals(target.getName()) &&
- target.getApiVersionNumber() >= getApiVersionNumber());
+ target.getVersion().getApiLevel() >= getVersion().getApiLevel());
}
return false;
}
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
@@ -250,7 +250,7 @@ final class AddOnTarget implements IAndroidTarget {
AddOnTarget addon = (AddOnTarget)obj;
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);
@@ -277,7 +277,7 @@ final class AddOnTarget implements IAndroidTarget {
// api version
if (value == 0) {
- value = getApiVersionNumber() - target.getApiVersionNumber();
+ value = getVersion().getApiLevel() - target.getVersion().getApiLevel();
}
return value;
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/AndroidVersion.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/AndroidVersion.java
new file mode 100644
index 0000000..5bd9aad
--- /dev/null
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/AndroidVersion.java
@@ -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;
+ }
+}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java
index f64b7ea..095a593 100644
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java
@@ -119,14 +119,14 @@ public interface IAndroidTarget extends Comparable<IAndroidTarget> {
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.
*/
- String getApiVersionName();
+ public String getVersionName();
/** Returns the revision number for the target. */
int getRevision();
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java
index ae621f3..911d379 100644
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java
@@ -26,32 +26,41 @@ import java.util.Map;
*/
final class PlatformTarget implements IAndroidTarget {
/** 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_NAME = "Android %s";
+ private final static String PLATFORM_NAME_PREVIEW = "Android %s (Preview)";
private final String mLocation;
private final String mName;
- private final int mApiVersionNumber;
- private final String mApiVersionName;
+ private final AndroidVersion mVersion;
+ private final String mVersionName;
private final int mRevision;
private final Map<String, String> mProperties;
private final Map<Integer, String> mPaths = new HashMap<Integer, String>();
private String[] mSkins;
+
PlatformTarget(String location, Map<String, String> properties,
- int apiNumber, String apiName, int revision) {
- mName = String.format(PLATFORM_NAME, apiName);
+ int apiLevel, String codeName, String versionName, int revision) {
if (location.endsWith(File.separator) == false) {
location = location + File.separator;
}
mLocation = location;
mProperties = Collections.unmodifiableMap(properties);
- mApiVersionNumber = apiNumber;
- mApiVersionName = apiName;
+ mVersion = new AndroidVersion(apiLevel, codeName);
+ mVersionName = versionName;
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
mPaths.put(ANDROID_JAR, mLocation + SdkConstants.FN_FRAMEWORK_LIBRARY);
mPaths.put(SOURCES, mLocation + SdkConstants.FD_ANDROID_SOURCES);
@@ -119,15 +128,15 @@ final class PlatformTarget implements IAndroidTarget {
* @see com.android.sdklib.IAndroidTarget#getDescription()
*/
public String getDescription() {
- return String.format("Standard Android platform %s", mApiVersionName);
+ return String.format("Standard Android platform %s", mVersionName);
}
- public int getApiVersionNumber(){
- return mApiVersionNumber;
+ public AndroidVersion getVersion() {
+ return mVersion;
}
- public String getApiVersionName() {
- return mApiVersionName;
+ public String getVersionName() {
+ return mVersionName;
}
public int getRevision() {
@@ -189,13 +198,23 @@ final class PlatformTarget implements IAndroidTarget {
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
// equal.
- return target.getApiVersionNumber() >= mApiVersionNumber;
+ return target.getVersion().getApiLevel() >= mVersion.getApiLevel();
}
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
@@ -206,10 +225,12 @@ final class PlatformTarget implements IAndroidTarget {
@Override
public boolean equals(Object obj) {
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 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.
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java
index 8c87d44..7df2512 100644
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java
@@ -42,6 +42,7 @@ import java.util.regex.Pattern;
public final class SdkManager {
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_REVISION = "ro.build.version.incremental";
@@ -263,23 +264,28 @@ public final class SdkManager {
if (map != null) {
// look for some specific values in the map.
+
+ // version string
String apiName = map.get(PROP_VERSION_RELEASE);
if (apiName == null) {
if (log != null) {
log.error(null,
"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;
}
+ // api level
int apiNumber;
String stringValue = map.get(PROP_VERSION_SDK);
if (stringValue == null) {
if (log != null) {
log.error(null,
"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;
} else {
@@ -291,19 +297,28 @@ public final class SdkManager {
if (log != null) {
log.error(null,
"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;
}
}
+ // 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;
stringValue = map.get(PROP_VERSION_REVISION);
if (stringValue == null) {
if (log != null) {
log.error(null,
"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;
} else {
@@ -346,6 +361,7 @@ public final class SdkManager {
platform.getAbsolutePath(),
map,
apiNumber,
+ apiCodename,
apiName,
revision);
@@ -435,8 +451,7 @@ public final class SdkManager {
try {
int apiValue = Integer.parseInt(api);
for (IAndroidTarget target : targetList) {
- if (target.isPlatform() &&
- target.getApiVersionNumber() == apiValue) {
+ if (target.isPlatform() && target.getVersion().equals(apiValue)) {
baseTarget = (PlatformTarget)target;
break;
}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonPackage.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonPackage.java
index 7908322..43228c0 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonPackage.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/AddonPackage.java
@@ -16,6 +16,7 @@
package com.android.sdklib.internal.repository;
+import com.android.sdklib.AndroidVersion;
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.SdkConstants;
import com.android.sdklib.SdkManager;
@@ -36,13 +37,12 @@ import java.util.Properties;
*/
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_VENDOR = "Addon.Vendor"; //$NON-NLS-1$
private final String mVendor;
private final String mName;
- private final int mApiLevel;
+ private final AndroidVersion mVersion;
/** An add-on library. */
public static class Lib {
@@ -74,7 +74,10 @@ public class AddonPackage extends Package {
super(source, packageNode, licenses);
mVendor = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_VENDOR);
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));
}
@@ -88,7 +91,7 @@ public class AddonPackage extends Package {
AddonPackage(IAndroidTarget target, Properties props) {
super( null, //source
props, //properties
- 0, //revision
+ target.getRevision(), //revision
null, //license
target.getDescription(), //description
null, //descUrl
@@ -97,7 +100,7 @@ public class AddonPackage extends Package {
target.getLocation() //archiveOsPath
);
- mApiLevel = target.getApiVersionNumber();
+ mVersion = target.getVersion();
mName = target.getName();
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.
- * 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
void saveProperties(Properties props) {
super.saveProperties(props);
- props.setProperty(PROP_API_LEVEL, Integer.toString(mApiLevel));
+ mVersion.saveProperties(props);
props.setProperty(PROP_NAME, mName);
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. */
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. */
@@ -214,7 +218,7 @@ public class AddonPackage extends Package {
// First find if this add-on is already installed. If so, reuse the same directory.
for (IAndroidTarget target : sdkManager.getTargets()) {
if (!target.isPlatform() &&
- target.getApiVersionNumber() == getApiLevel() &&
+ target.getVersion().equals(mVersion) &&
target.getName().equals(getName()) &&
target.getVendor().equals(getVendor())) {
return new File(target.getLocation());
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/PlatformPackage.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/PlatformPackage.java
index 1c0a638..3f36596 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/PlatformPackage.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/PlatformPackage.java
@@ -16,6 +16,7 @@
package com.android.sdklib.internal.repository;
+import com.android.sdklib.AndroidVersion;
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.SdkConstants;
import com.android.sdklib.SdkManager;
@@ -34,11 +35,10 @@ import java.util.Properties;
*/
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 final String mVersion;
- private final int mApiLevel;
+ private final AndroidVersion mVersion;
+ private final String mVersionName;
/**
* 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) {
super(source, packageNode, licenses);
- mVersion = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_VERSION);
- mApiLevel = XmlParserUtils.getXmlInt (packageNode, SdkRepository.NODE_API_LEVEL, 0);
+ mVersionName = XmlParserUtils.getXmlString(packageNode, SdkRepository.NODE_VERSION);
+ 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) {
super( null, //source
props, //properties
- 0, //revision
+ target.getRevision(), //revision
null, //license
target.getDescription(), //description
null, //descUrl
@@ -69,37 +74,43 @@ public class PlatformPackage extends Package {
target.getLocation() //archiveOsPath
);
- mApiLevel = target.getApiVersionNumber();
- mVersion = target.getApiVersionName();
+ mVersion = target.getVersion();
+ mVersionName = target.getVersionName();
}
/**
* 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
void saveProperties(Properties props) {
super.saveProperties(props);
- props.setProperty(PROP_API_LEVEL, Integer.toString(mApiLevel));
- props.setProperty(PROP_VERSION, mVersion);
+ mVersion.saveProperties(props);
+ props.setProperty(PROP_VERSION, mVersionName);
}
/** Returns the version, a string, for platform packages. */
- public String getVersion() {
- return mVersion;
+ public String getVersionName() {
+ return mVersionName;
}
/** Returns the api-level, an int > 0, for platform, add-on and doc packages. */
public int getApiLevel() {
- return mApiLevel;
+ // FIXME: return the AndroidVersion instead.
+ return mVersion.getApiLevel();
}
/** Returns a short description for an {@link IDescription}. */
@Override
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",
- getVersion(),
+ getVersionName(),
getApiLevel());
}
@@ -128,17 +139,17 @@ public class PlatformPackage extends Package {
@Override
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()) {
if (target.isPlatform() &&
- target.getApiVersionNumber() == getApiLevel() &&
- target.getApiVersionName().equals(getVersion())) {
+ target.getVersion().equals(mVersion) &&
+ target.getVersionName().equals(getVersionName())) {
return new File(target.getLocation());
}
}
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;
}
@@ -162,7 +173,7 @@ public class PlatformPackage extends Package {
}
PlatformPackage newPkg = (PlatformPackage) replacementPackage;
- return newPkg.getVersion().equalsIgnoreCase(this.getVersion()) &&
+ return newPkg.getVersionName().equalsIgnoreCase(this.getVersionName()) &&
newPkg.getApiLevel() == this.getApiLevel() &&
newPkg.getRevision() > this.getRevision();
}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/SdkRepository.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/SdkRepository.java
index 9760444..3e9ab99 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/SdkRepository.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/SdkRepository.java
@@ -63,6 +63,8 @@ public class SdkRepository {
public static final String NODE_VERSION = "version"; //$NON-NLS-1$
/** 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$
+ /** 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. */
public static final String NODE_VENDOR = "vendor"; //$NON-NLS-1$
/** The name, a string, for add-on packages or for libraries. */
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/sdk-repository.xsd b/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/sdk-repository.xsd
index c55e7d5..920823a 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/sdk-repository.xsd
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/repository/sdk-repository.xsd
@@ -52,6 +52,8 @@
<xsd:element name="version" type="xsd:normalizedString" />
<!-- The Android API Level for the platform. An int > 0. -->
<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
package is generated. -->
diff --git a/sdkmanager/libs/sdklib/tests/com/android/sdklib/repository/repository_sample.xml b/sdkmanager/libs/sdklib/tests/com/android/sdklib/repository/repository_sample.xml
index d4eacf9..68e8efd 100755
--- a/sdkmanager/libs/sdklib/tests/com/android/sdklib/repository/repository_sample.xml
+++ b/sdkmanager/libs/sdklib/tests/com/android/sdklib/repository/repository_sample.xml
@@ -156,6 +156,24 @@
</sdk:libs>
<sdk:uses-license ref="license2" />
</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:revision>1</sdk:revision>
diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdCreationDialog.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdCreationDialog.java
index 8804c70..3c0369f 100644
--- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdCreationDialog.java
+++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdCreationDialog.java
@@ -273,14 +273,14 @@ final class AvdCreationDialog extends Dialog {
for (IAndroidTarget target : sdkManager.getTargets()) {
String name;
if (target.isPlatform()) {
- name = String.format("%s - API Level %d",
+ name = String.format("%s - API Level %s",
target.getName(),
- target.getApiVersionNumber());
+ target.getVersion().getApiString());
} else {
- name = String.format("%s (%s) - API Level %d",
+ name = String.format("%s (%s) - API Level %s",
target.getName(),
target.getVendor(),
- target.getApiVersionNumber());
+ target.getVersion().getApiString());
}
mCurrentTargets.put(name, target);
mTargetCombo.add(name);
diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdDetailsDialog.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdDetailsDialog.java
index 8b054f2..a845056 100644
--- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdDetailsDialog.java
+++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdDetailsDialog.java
@@ -16,6 +16,7 @@
package com.android.sdkuilib.internal.widgets;
+import com.android.sdklib.AndroidVersion;
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.internal.avd.AvdManager;
import com.android.sdklib.internal.avd.AvdManager.AvdInfo;
@@ -106,8 +107,9 @@ final class AvdDetailsDialog extends Dialog {
displayValue(c, "Error:", mAvdInfo.getErrorMessage());
} else {
IAndroidTarget target = mAvdInfo.getTarget();
- displayValue(c, "Target:", String.format("%s (API level %d)",
- target.getName(), target.getApiVersionNumber()));
+ AndroidVersion version = target.getVersion();
+ displayValue(c, "Target:", String.format("%s (API level %s)",
+ target.getName(), version.getApiString()));
// display some extra values.
Map<String, String> properties = mAvdInfo.getProperties();
diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java
index 8826b4c..b27636c 100644
--- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java
+++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java
@@ -723,8 +723,8 @@ public final class AvdSelector {
IAndroidTarget target = avd.getTarget();
if (target != null) {
item.setText(1, target.getFullName());
- item.setText(2, target.getApiVersionName());
- item.setText(3, Integer.toString(target.getApiVersionNumber()));
+ item.setText(2, target.getVersionName());
+ item.setText(3, target.getVersion().getApiString());
} else {
item.setText(1, "?");
item.setText(2, "?");
diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/SdkTargetSelector.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/SdkTargetSelector.java
index bf420f3..e82eb29 100644
--- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/SdkTargetSelector.java
+++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/SdkTargetSelector.java
@@ -323,8 +323,8 @@ public class SdkTargetSelector {
item.setData(target);
item.setText(0, target.getName());
item.setText(1, target.getVendor());
- item.setText(2, target.getApiVersionName());
- item.setText(3, Integer.toString(target.getApiVersionNumber()));
+ item.setText(2, target.getVersionName());
+ item.setText(3, target.getVersion().getApiString());
}
} else {
table.setEnabled(false);