Parse the manifest min/targetSdkVersion to configure the layoutlib.

This is needed to configure ApplicationInfo in the layoutlib
so that some widgets properly apply different behaviors based
on the app targetSdkVersion.

Change-Id: Ic78af4390d1b871469583f3efc0de3a9da718a6c
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutReloadMonitor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutReloadMonitor.java
index 48d6cb4..eafc910 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutReloadMonitor.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutReloadMonitor.java
@@ -28,6 +28,7 @@
 import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager.IResourceListener;
 import com.android.ide.eclipse.adt.internal.sdk.ProjectState;
 import com.android.ide.eclipse.adt.internal.sdk.Sdk;
+import com.android.sdklib.SdkConstants;
 
 import org.eclipse.core.resources.IFile;
 import org.eclipse.core.resources.IMarkerDelta;
@@ -64,9 +65,10 @@
         public boolean layout = false;
         public boolean rClass = false;
         public boolean localeList = false;
+        public boolean manifest = false;
 
         boolean isAllTrue() {
-            return code && resources && rClass && localeList;
+            return code && resources && rClass && localeList && manifest;
         }
     }
 
@@ -237,6 +239,16 @@
 
                     changeFlags.code = true;
                 }
+            } else if (SdkConstants.FN_ANDROID_MANIFEST_XML.equals(file.getName()) &&
+                    file.getParent().equals(project)) {
+                // this is a manifest change!
+                if (changeFlags == null) {
+                    changeFlags = new ChangeFlags();
+                    mProjectFlags.put(project, changeFlags);
+                }
+
+                changeFlags.manifest = true;
+
             }
         }
     };
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java
index 15d46e9..f396a71 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java
@@ -67,8 +67,13 @@
 import com.android.ide.eclipse.adt.internal.sdk.Sdk;
 import com.android.ide.eclipse.adt.internal.sdk.Sdk.ITargetChangeListener;
 import com.android.ide.eclipse.adt.io.IFileWrapper;
+import com.android.ide.eclipse.adt.io.IFolderWrapper;
 import com.android.sdklib.IAndroidTarget;
 import com.android.sdklib.SdkConstants;
+import com.android.sdklib.io.IAbstractFile;
+import com.android.sdklib.io.StreamException;
+import com.android.sdklib.xml.AndroidManifest;
+import com.android.sdklib.xml.AndroidManifestParser;
 import com.android.sdkuilib.internal.widgets.ResolutionChooserDialog;
 
 import org.eclipse.core.resources.IFile;
@@ -138,6 +143,8 @@
 import java.util.Map;
 import java.util.Set;
 
+import javax.xml.xpath.XPathExpressionException;
+
 /**
  * Graphical layout editor part, version 2.
  * <p/>
@@ -242,6 +249,9 @@
     private CustomButton mZoomFitButton;
     private CustomButton mClippingButton;
 
+    private int mMinSdkVersion;
+    private int mTargetSdkVersion;
+
     public GraphicalEditorPart(LayoutEditor layoutEditor) {
         mLayoutEditor = layoutEditor;
         setPartName("Graphical Layout");
@@ -1080,6 +1090,8 @@
                 AdtPlugin.log(e, "Can't access session property %1$s", NAME_INCLUDE);
             }
         }
+
+        computeSdkVersion();
     }
 
     /**
@@ -1089,6 +1101,7 @@
     public void replaceFile(IFile file) {
         mEditedFile = file;
         mConfigComposite.replaceFile(mEditedFile);
+        computeSdkVersion();
     }
 
     /**
@@ -1642,8 +1655,8 @@
                 density, xdpi, ydpi,
                 resolver,
                 mProjectCallback,
-                1 /*minSdkVersion*/,
-                1 /*targetSdkVersion */,
+                mMinSdkVersion,
+                mTargetSdkVersion,
                 logger);
 
         if (transparentBackground) {
@@ -1774,6 +1787,10 @@
                 }
             }
 
+            if (flags.manifest) {
+                recompute |= computeSdkVersion();
+            }
+
             if (recompute) {
                 if (mLayoutEditor.isGraphicalEditorActive()) {
                     recomputeLayout();
@@ -2363,4 +2380,51 @@
     public FolderConfiguration getConfiguration() {
         return mConfigComposite.getCurrentConfig();
     }
+
+
+    /**
+     * Figures out the project's minSdkVersion and targetSdkVersion and return whether the values
+     * have changed.
+     */
+    private boolean computeSdkVersion() {
+        int oldMinSdkVersion = mMinSdkVersion;
+        int oldTargetSdkVersion = mTargetSdkVersion;
+
+        IAbstractFile manifestFile = AndroidManifestParser.getManifest(
+                new IFolderWrapper(mEditedFile.getProject()));
+
+        if (manifestFile != null) {
+            try {
+                Object value = AndroidManifest.getMinSdkVersion(manifestFile);
+                if (value instanceof Integer) {
+                    mMinSdkVersion = ((Integer) value).intValue();
+                } else if (value instanceof String) {
+                    // handle codename
+                    IAndroidTarget target = Sdk.getCurrent().getTargetFromHashString(
+                            "android-" + value); //$NON-NLS-1$
+                    if (target == null) {
+                        mMinSdkVersion = 1; // missing value? same as api 1
+                    } else {
+                        // codename future API level is current api + 1
+                        mMinSdkVersion = target.getVersion().getApiLevel() + 1;
+                    }
+                } else {
+                    mMinSdkVersion = 1; // missing value? same as api 1
+                }
+
+                Integer i = AndroidManifest.getTargetSdkVersion(manifestFile);
+                if (i == null) {
+                    mTargetSdkVersion = mMinSdkVersion;
+                } else {
+                    mTargetSdkVersion = i.intValue();
+                }
+            } catch (XPathExpressionException e) {
+                // do nothing we'll use 1 below.
+            } catch (StreamException e) {
+                // do nothing we'll use 1 below.
+            }
+        }
+
+        return oldMinSdkVersion != mMinSdkVersion || oldTargetSdkVersion != mTargetSdkVersion;
+    }
 }
diff --git a/files/sdk.properties b/files/sdk.properties
index efa50d9..a1affe4 100644
--- a/files/sdk.properties
+++ b/files/sdk.properties
@@ -1,4 +1,4 @@
-# SDK properties
-# This file is copied in the root folder of each platform component.
-# If it used by various tools to figure out what the platform can do.
-sdk.ant.templates.revision=1
\ No newline at end of file
+# THIS FILE IS OBSOLETE AND IS ONLY THERE TO BUILD
+# OLDER VERSION OF THE PLATFORM
+#
+# THE NEW FILE IS LOCATED IN development.git/sdk
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/xml/AndroidManifest.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/xml/AndroidManifest.java
index 4012300..6ed6e49 100644
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/xml/AndroidManifest.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/xml/AndroidManifest.java
@@ -183,14 +183,20 @@
     }
 
     /**
-     * Returns the value of the minSdkVersion attribute (defaults to 1 if the attribute is not set),
-     * or -1 if the value is a codename.
+     * Returns the value of the minSdkVersion attribute.
+     * <p/>
+     * If the attribute is set with an int value, the method returns an Integer object.
+     * <p/>
+     * If the attribute is set with a codename, it returns the codename as a String object.
+     * <p/>
+     * If the attribute is not set, it returns null.
+     *
      * @param manifestFile the manifest file to read the attribute from.
-     * @return the integer value or -1 if not set.
+     * @return the attribute value.
      * @throws XPathExpressionException
      * @throws StreamException If any error happens when reading the manifest.
      */
-    public static int getMinSdkVersion(IAbstractFile manifestFile)
+    public static Object getMinSdkVersion(IAbstractFile manifestFile)
             throws XPathExpressionException, StreamException {
         XPath xPath = AndroidXPathFactory.newXPath();
 
@@ -202,9 +208,35 @@
                 new InputSource(manifestFile.getContents()));
 
         try {
-            return Integer.parseInt(result);
+            return Integer.valueOf(result);
         } catch (NumberFormatException e) {
-            return result.length() > 0 ? -1 : 1;
+            return result.length() > 0 ? result : null;
+        }
+    }
+
+    /**
+     * Returns the value of the targetSdkVersion attribute (defaults to 1 if the attribute is
+     * not set), or -1 if the value is a codename.
+     * @param manifestFile the manifest file to read the attribute from.
+     * @return the integer value or -1 if not set.
+     * @throws XPathExpressionException
+     * @throws StreamException If any error happens when reading the manifest.
+     */
+    public static Integer getTargetSdkVersion(IAbstractFile manifestFile)
+            throws XPathExpressionException, StreamException {
+        XPath xPath = AndroidXPathFactory.newXPath();
+
+        String result = xPath.evaluate(
+                "/"  + NODE_MANIFEST +
+                "/"  + NODE_USES_SDK +
+                "/@" + AndroidXPathFactory.DEFAULT_NS_PREFIX +
+                ":"  + ATTRIBUTE_TARGET_SDK_VERSION,
+                new InputSource(manifestFile.getContents()));
+
+        try {
+            return Integer.valueOf(result);
+        } catch (NumberFormatException e) {
+            return result.length() > 0 ? -1 : null;
         }
     }