am 55899308: Merge change 3342 into donut

Merge commit '5589930805c71791ecdd3c4847bd18aab5eed937'

* commit '5589930805c71791ecdd3c4847bd18aab5eed937':
  Add revision to Android targets.
diff --git a/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java b/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java
index 26af498..1836d33 100644
--- a/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java
+++ b/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java
@@ -386,9 +386,11 @@
             if (target.isPlatform()) {
                 mSdkLog.printf("     Type: Platform\n");
                 mSdkLog.printf("     API level: %d\n", target.getApiVersionNumber());
+                mSdkLog.printf("     Revision: %d\n", target.getRevision());
             } else {
                 mSdkLog.printf("     Type: Add-On\n");
                 mSdkLog.printf("     Vendor: %s\n", target.getVendor());
+                mSdkLog.printf("     Revision: %d\n", target.getRevision());
                 if (target.getDescription() != null) {
                     mSdkLog.printf("     Description: %s\n", target.getDescription());
                 }
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java
index c02c247..3ac0d1a 100644
--- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java
@@ -68,6 +68,7 @@
     private final PlatformTarget mBasePlatform;
     private final String mName;
     private final String mVendor;
+    private final int mRevision;
     private final String mDescription;
     private String[] mSkins;
     private String mDefaultSkin;
@@ -79,12 +80,13 @@
      * @param location the OS path location of the add-on
      * @param name the name of the add-on
      * @param vendor the vendor name of the add-on
+     * @param revision the revision of the add-on
      * @param description the add-on description
      * @param libMap A map containing the optional libraries. The map key is the fully-qualified
      * library name. The value is a 2 string array with the .jar filename, and the description.
      * @param basePlatform the platform the add-on is extending.
      */
-    AddOnTarget(String location, String name, String vendor, String description,
+    AddOnTarget(String location, String name, String vendor, int revision, String description,
             Map<String, String[]> libMap, PlatformTarget basePlatform) {
         if (location.endsWith(File.separator) == false) {
             location = location + File.separator;
@@ -93,6 +95,7 @@
         mLocation = location;
         mName = name;
         mVendor = vendor;
+        mRevision = revision;
         mDescription = description;
         mBasePlatform = basePlatform;
 
@@ -144,6 +147,10 @@
         return mBasePlatform.getApiVersionNumber();
     }
 
+    public int getRevision() {
+        return mRevision;
+    }
+
     public boolean isPlatform() {
         return false;
     }
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java
index d988340..f64b7ea 100644
--- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java
@@ -76,10 +76,15 @@
      */
     public final static int NO_USB_ID = 0;
 
+    /** An optional library provided by an Android Target */
     public interface IOptionalLibrary {
+        /** The name of the library, as used in the manifest (&lt;uses-library&gt;). */
         String getName();
+        /** The file name of the jar file. */
         String getJarName();
+        /** Absolute OS path to the jar file. */
         String getJarPath();
+        /** Description of the library. */
         String getDescription();
     }
 
@@ -123,6 +128,9 @@
      */
     String getApiVersionName();
 
+    /** Returns the revision number for the target. */
+    int getRevision();
+
     /**
      * Returns true if the target is a standard Android platform.
      */
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java
index bbb3cd7..ae621f3 100644
--- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/PlatformTarget.java
@@ -35,12 +35,13 @@
     private final String mName;
     private final int mApiVersionNumber;
     private final String mApiVersionName;
+    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 apiNumber, String apiName, int revision) {
         mName = String.format(PLATFORM_NAME, apiName);
         if (location.endsWith(File.separator) == false) {
             location = location + File.separator;
@@ -49,6 +50,7 @@
         mProperties = Collections.unmodifiableMap(properties);
         mApiVersionNumber = apiNumber;
         mApiVersionName = apiName;
+        mRevision = revision;
 
         // pre-build the path to the platform components
         mPaths.put(ANDROID_JAR, mLocation + SdkConstants.FN_FRAMEWORK_LIBRARY);
@@ -128,6 +130,10 @@
         return mApiVersionName;
     }
 
+    public int getRevision() {
+        return mRevision;
+    }
+
     public boolean isPlatform() {
         return true;
     }
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java
index ebafa77..7a0b06b 100644
--- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java
@@ -43,6 +43,7 @@
 
     public final static String PROP_VERSION_SDK = "ro.build.version.sdk";
     public final static String PROP_VERSION_RELEASE = "ro.build.version.release";
+    public final static String PROP_VERSION_REVISION = "ro.build.version.incremental";
 
     private final static String ADDON_NAME = "name";
     private final static String ADDON_VENDOR = "vendor";
@@ -51,6 +52,8 @@
     private final static String ADDON_LIBRARIES = "libraries";
     private final static String ADDON_DEFAULT_SKIN = "skin";
     private final static String ADDON_USB_VENDOR = "usb-vendor";
+    private final static String ADDON_REVISION = "revision";
+    private final static String ADDON_REVISION_OLD = "version";
 
     private final static Pattern PATTERN_PROP = Pattern.compile(
             "^([a-zA-Z0-9._-]+)\\s*=\\s*(.*)\\s*$");
@@ -58,6 +61,9 @@
     private final static Pattern PATTERN_LIB_DATA = Pattern.compile(
             "^([a-zA-Z0-9._-]+\\.jar);(.*)$", Pattern.CASE_INSENSITIVE);
 
+    private final static Pattern PATTERN_LOCAL_BUILD_PATTERN = Pattern.compile(
+            "^\\S+\\.\\S+\\.(\\d+)\\.\\d+$");
+
      // usb ids are 16-bit hexadecimal values.
     private final static Pattern PATTERN_USB_IDS = Pattern.compile(
             "^0x[a-f0-9]{4}$", Pattern.CASE_INSENSITIVE);
@@ -234,36 +240,97 @@
 
             if (map != null) {
                 // look for some specific values in the map.
-                try {
-                    String apiNumber = map.get(PROP_VERSION_SDK);
-                    String apiName = map.get(PROP_VERSION_RELEASE);
-                    if (apiNumber != null && apiName != null) {
-                        // api number and name looks valid, perform a few more checks
-                        if (checkPlatformContent(platform, log) == false) {
-                            return null;
-                        }
-                        // create the target.
-                        PlatformTarget target = new PlatformTarget(
-                                platform.getAbsolutePath(),
-                                map,
-                                Integer.parseInt(apiNumber),
-                                apiName);
-
-                        // need to parse the skins.
-                        String[] skins = parseSkinFolder(target.getPath(IAndroidTarget.SKINS));
-                        target.setSkins(skins);
-
-                        return target;
-                    }
-                } catch (NumberFormatException e) {
-                    // looks like apiNumber does not parse to a number.
-                    // Ignore this platform.
+                String apiName = map.get(PROP_VERSION_RELEASE);
+                if (apiName == null) {
                     if (log != null) {
                         log.error(null,
-                                "Ignoring platform '%1$s': %2$s is not a valid number in %3$s.",
+                                "Ignoring platform '%1$s': %2$s is missing from '%3$s'",
+                                platform.getName(), PROP_VERSION_RELEASE, SdkConstants.FN_BUILD_PROP);
+                    }
+                    return null;
+                }
+
+                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);
                     }
+                    return null;
+                } else {
+                    try {
+                         apiNumber = Integer.parseInt(stringValue);
+                    } catch (NumberFormatException e) {
+                        // looks like apiNumber does not parse to a number.
+                        // Ignore this platform.
+                        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);
+                        }
+                        return null;
+                    }
                 }
+
+                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);
+                    }
+                    return null;
+                } else {
+                    try {
+                         revision = Integer.parseInt(stringValue);
+                    } catch (NumberFormatException e) {
+                        // looks like the revision does not parse to a number.
+                        // we look if it's a local build in the format
+                        // <buildtype>.<username>.<date>.<time>
+                        Matcher m = PATTERN_LOCAL_BUILD_PATTERN.matcher(stringValue);
+                        boolean valid = false;
+                        if (m.matches()) {
+                            String date = m.group(1);
+                            try {
+                                revision = Integer.parseInt(date);
+                                valid = true;
+                            } catch (NumberFormatException e2) {
+                                // do nothing, we'll display an error and return below
+                            }
+                        }
+
+                        if (valid == false) {
+                            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);
+                            }
+                            return null;
+                        }
+                    }
+                }
+
+                // api number and name look valid, perform a few more checks
+                if (checkPlatformContent(platform, log) == false) {
+                    return null;
+                }
+                // create the target.
+                PlatformTarget target = new PlatformTarget(
+                        platform.getAbsolutePath(),
+                        map,
+                        apiNumber,
+                        apiName,
+                        revision);
+
+                // need to parse the skins.
+                String[] skins = parseSkinFolder(target.getPath(IAndroidTarget.SKINS));
+                target.setSkins(skins);
+
+                return target;
             }
         } else if (log != null) {
             log.error(null, "Ignoring platform '%1$s': %2$s is missing.", platform.getName(),
@@ -374,6 +441,27 @@
                 // get the optional description
                 String description = propertyMap.get(ADDON_DESCRIPTION);
 
+                // get the add-on revision
+                int revisionValue = 1;
+                String revision = propertyMap.get(ADDON_REVISION);
+                if (revision == null) {
+                    revision = propertyMap.get(ADDON_REVISION_OLD);
+                }
+                if (revision != null) {
+                    try {
+                        revisionValue = Integer.parseInt(revision);
+                    } catch (NumberFormatException e) {
+                        // looks like apiNumber does not parse to a number.
+                        // Ignore this add-on.
+                        if (log != null) {
+                            log.error(null,
+                                    "Ignoring add-on '%1$s': %2$s is not a valid number in %3$s.",
+                                    addon.getName(), ADDON_REVISION, SdkConstants.FN_BUILD_PROP);
+                        }
+                        return null;
+                    }
+                }
+
                 // get the optional libraries
                 String librariesValue = propertyMap.get(ADDON_LIBRARIES);
                 Map<String, String[]> libMap = null;
@@ -413,7 +501,7 @@
                 }
 
                 AddOnTarget target = new AddOnTarget(addon.getAbsolutePath(), name, vendor,
-                        description, libMap, baseTarget);
+                        revisionValue, description, libMap, baseTarget);
 
                 // need to parse the skins.
                 String[] skins = parseSkinFolder(target.getPath(IAndroidTarget.SKINS));