Sample code to use the layout rendering library.

This is very basic sample code showing how to render
a layout.

This explains how to load the resources, create Folderconfig,
ResourceResolver, and how to call the LayoutLibrary to do an
actual render.

There are some big limitations:
- can't render custom views because there's nothing
  compiling them and generating the compiled R.class
  file.
- not all features of ADT are present because there
  are things that don't make sense outside of an editor
  (render in context, expand empty layouts, etc...)

Change-Id: I0c8676ebfbff27f0e9412bb4b13193ce64082372
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderService.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderService.java
index a03d038..4b743b4 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderService.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderService.java
@@ -46,8 +46,6 @@
 import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo;
 import com.android.ide.eclipse.adt.internal.editors.uimodel.UiDocumentNode;
 import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
-import com.android.ide.eclipse.adt.internal.resources.manager.ProjectResources;
-import com.android.ide.eclipse.adt.internal.resources.manager.ResourceManager;
 import com.android.resources.Density;
 
 import org.eclipse.core.resources.IProject;
@@ -273,12 +271,6 @@
             return null;
         }
 
-        ProjectResources projectRes = ResourceManager.getInstance().getProjectResources(mProject);
-        if (projectRes == null) {
-            mLogger.error(null, "Missing project resources.", null);
-            return null;
-        }
-
         int width = mWidth;
         int height = mHeight;
         if (mUseExplodeMode) {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceManager.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceManager.java
index cacd8e2..7935800 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceManager.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceManager.java
@@ -16,8 +16,6 @@
 
 package com.android.ide.eclipse.adt.internal.resources.manager;
 
-import com.android.annotations.VisibleForTesting;
-import com.android.annotations.VisibleForTesting.Visibility;
 import com.android.ide.common.resources.FrameworkResources;
 import com.android.ide.common.resources.ResourceFile;
 import com.android.ide.common.resources.ResourceFolder;
@@ -32,9 +30,6 @@
 import com.android.ide.eclipse.adt.io.IFileWrapper;
 import com.android.ide.eclipse.adt.io.IFolderWrapper;
 import com.android.io.FolderWrapper;
-import com.android.io.IAbstractFile;
-import com.android.io.IAbstractFolder;
-import com.android.io.IAbstractResource;
 import com.android.resources.ResourceFolderType;
 import com.android.sdklib.IAndroidTarget;
 import com.android.sdklib.SdkConstants;
@@ -49,7 +44,6 @@
 import org.eclipse.core.runtime.CoreException;
 import org.eclipse.core.runtime.IPath;
 
-import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -417,7 +411,7 @@
             FrameworkResources resources = new FrameworkResources();
 
             try {
-                loadResources(resources, frameworkRes);
+                resources.loadResources(frameworkRes);
                 resources.loadPublicResources(frameworkRes, AdtPlugin.getDefault());
                 return resources;
             } catch (IOException e) {
@@ -430,51 +424,6 @@
     }
 
     /**
-     * Loads the resources from a folder, and fills the given {@link ResourceRepository}.
-     * <p/>
-     * This is mostly a utility method that should not be used to process actual Eclipse projects
-     * (Those are loaded with {@link #createProject(IProject)} for new project or
-     * {@link #processFolder(IAbstractFolder, ProjectResources)} and
-     * {@link #processFile(IAbstractFile, ResourceFolder)} for folder/file modifications)<br>
-     * This method will process files/folders with implementations of {@link IAbstractFile} and
-     * {@link IAbstractFolder} based on {@link File} instead of {@link IFile} and {@link IFolder}
-     * respectively. This is not proper for handling {@link IProject}s.
-     * </p>
-     * This is used to load the framework resources, or to do load project resources when
-     * setting rendering tests.
-     *
-     *
-     * @param resources The {@link ResourceRepository} files to fill.
-     *       This is filled up with the content of the folder.
-     * @param rootFolder The folder to read the resources from. This is the top level
-     * resource folder (res/)
-     * @throws IOException
-     */
-    @VisibleForTesting(visibility=Visibility.PRIVATE)
-    public void loadResources(ResourceRepository resources, IAbstractFolder rootFolder)
-            throws IOException {
-        IAbstractResource[] files = rootFolder.listMembers();
-        for (IAbstractResource file : files) {
-            if (file instanceof IAbstractFolder) {
-                IAbstractFolder folder = (IAbstractFolder) file;
-                ResourceFolder resFolder = resources.processFolder(folder);
-
-                if (resFolder != null) {
-                    // now we process the content of the folder
-                    IAbstractResource[] children = folder.listMembers();
-
-                    for (IAbstractResource childRes : children) {
-                        if (childRes instanceof IAbstractFile) {
-                            resFolder.processFile((IAbstractFile) childRes,
-                                    ResourceHelper.getResourceDeltaKind(IResourceDelta.ADDED));
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    /**
      * Initial project parsing to gather resource info.
      * @param project
      */
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/tests/functests/layoutRendering/ApiDemosRenderingTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/tests/functests/layoutRendering/ApiDemosRenderingTest.java
index e38dfb9..1887d9c 100644
--- a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/tests/functests/layoutRendering/ApiDemosRenderingTest.java
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/tests/functests/layoutRendering/ApiDemosRenderingTest.java
@@ -32,6 +32,7 @@
 import com.android.ide.common.resources.configuration.FolderConfiguration;
 import com.android.ide.common.resources.configuration.KeyboardStateQualifier;
 import com.android.ide.common.resources.configuration.NavigationMethodQualifier;
+import com.android.ide.common.resources.configuration.NavigationStateQualifier;
 import com.android.ide.common.resources.configuration.ScreenDimensionQualifier;
 import com.android.ide.common.resources.configuration.ScreenHeightQualifier;
 import com.android.ide.common.resources.configuration.ScreenOrientationQualifier;
@@ -51,6 +52,7 @@
 import com.android.resources.Keyboard;
 import com.android.resources.KeyboardState;
 import com.android.resources.Navigation;
+import com.android.resources.NavigationState;
 import com.android.resources.ResourceType;
 import com.android.resources.ScreenOrientation;
 import com.android.resources.ScreenRatio;
@@ -204,7 +206,7 @@
 
         // now load the project resources
         ProjectResources project = new ProjectResources(null /*project*/);
-        ResourceManager.getInstance().loadResources(project, resFolder);
+        project.loadResources(resFolder);
 
         // Create a folder configuration that will be used for the rendering:
         FolderConfiguration config = getConfiguration();
@@ -287,9 +289,12 @@
         config.addQualifier(new TouchScreenQualifier(TouchScreen.FINGER));
         config.addQualifier(new KeyboardStateQualifier(KeyboardState.HIDDEN));
         config.addQualifier(new TextInputMethodQualifier(Keyboard.QWERTY));
+        config.addQualifier(new NavigationStateQualifier(NavigationState.HIDDEN));
         config.addQualifier(new NavigationMethodQualifier(Navigation.TRACKBALL));
         config.addQualifier(new ScreenDimensionQualifier(480, 320));
 
+        config.updateScreenWidthAndHeight();
+
         return config;
     }
 }
diff --git a/ide_common/src/com/android/ide/common/resources/ResourceRepository.java b/ide_common/src/com/android/ide/common/resources/ResourceRepository.java
index f72ebd2..0acc016 100644
--- a/ide_common/src/com/android/ide/common/resources/ResourceRepository.java
+++ b/ide_common/src/com/android/ide/common/resources/ResourceRepository.java
@@ -22,11 +22,14 @@
 import com.android.ide.common.resources.configuration.FolderConfiguration;
 import com.android.ide.common.resources.configuration.LanguageQualifier;
 import com.android.ide.common.resources.configuration.RegionQualifier;
+import com.android.io.IAbstractFile;
 import com.android.io.IAbstractFolder;
+import com.android.io.IAbstractResource;
 import com.android.resources.FolderTypeRelationship;
 import com.android.resources.ResourceFolderType;
 import com.android.resources.ResourceType;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -459,6 +462,38 @@
         return set;
     }
 
+    /**
+     * Loads the resources from a resource folder.
+     * <p/>
+     *
+     * @param rootFolder The folder to read the resources from. This is the top level
+     * resource folder (res/)
+     * @throws IOException
+     */
+    public void loadResources(IAbstractFolder rootFolder)
+            throws IOException {
+        IAbstractResource[] files = rootFolder.listMembers();
+        for (IAbstractResource file : files) {
+            if (file instanceof IAbstractFolder) {
+                IAbstractFolder folder = (IAbstractFolder) file;
+                ResourceFolder resFolder = processFolder(folder);
+
+                if (resFolder != null) {
+                    // now we process the content of the folder
+                    IAbstractResource[] children = folder.listMembers();
+
+                    for (IAbstractResource childRes : children) {
+                        if (childRes instanceof IAbstractFile) {
+                            resFolder.processFile((IAbstractFile) childRes,
+                                    ResourceDeltaKind.ADDED);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+
     protected void removeFile(Collection<ResourceType> types, ResourceFile file) {
         for (ResourceType type : types) {
             removeFile(type, file);
diff --git a/layoutlib_api/sample/.classpath b/layoutlib_api/sample/.classpath
new file mode 100644
index 0000000..47c38c1
--- /dev/null
+++ b/layoutlib_api/sample/.classpath
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="var" path="ANDROID_SRC/prebuilt/common/kxml2/kxml2-2.3.0.jar" sourcepath="/ANDROID_SRC/dalvik/libcore/xml/src/main/java"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/common"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/ide_common"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/layoutlib_api"/>
+	<classpathentry combineaccessrules="false" kind="src" path="/SdkLib"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/layoutlib_api/sample/.project b/layoutlib_api/sample/.project
new file mode 100644
index 0000000..1cc19f5
--- /dev/null
+++ b/layoutlib_api/sample/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>layoutlib_sample</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
diff --git a/layoutlib_api/sample/README.txt b/layoutlib_api/sample/README.txt
new file mode 100644
index 0000000..84570a3
--- /dev/null
+++ b/layoutlib_api/sample/README.txt
@@ -0,0 +1,16 @@
+Sample code to use the layout rendering library.
+
+This is very basic sample code showing how to render
+a layout.
+
+This explains how to load the resources, create Folderconfig,
+ResourceResolver, and how to call the LayoutLibrary to do an
+actual render.
+
+There are some big limitations:
+- can't render custom views because there's nothing
+compiling them and generating the compiled R.class
+file.
+- not all features of ADT are present because there
+are things that don't make sense outside of an editor
+(render in context, expand empty layouts, etc...)
\ No newline at end of file
diff --git a/layoutlib_api/sample/src/com/example/android/render/Main.java b/layoutlib_api/sample/src/com/example/android/render/Main.java
new file mode 100644
index 0000000..93ee8a9
--- /dev/null
+++ b/layoutlib_api/sample/src/com/example/android/render/Main.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2011 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.example.android.render;
+
+import com.android.ide.common.rendering.api.RenderSession;
+import com.android.ide.common.rendering.api.Result;
+import com.android.ide.common.rendering.api.ViewInfo;
+import com.android.ide.common.resources.ResourceItem;
+import com.android.ide.common.resources.ResourceRepository;
+import com.android.ide.common.resources.ResourceResolver;
+import com.android.ide.common.resources.configuration.FolderConfiguration;
+import com.android.io.FolderWrapper;
+import com.android.resources.Density;
+import com.android.resources.Keyboard;
+import com.android.resources.KeyboardState;
+import com.android.resources.Navigation;
+import com.android.resources.NavigationState;
+import com.android.resources.ScreenOrientation;
+import com.android.resources.ScreenRatio;
+import com.android.resources.ScreenSize;
+import com.android.resources.TouchScreen;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.util.List;
+
+import javax.imageio.ImageIO;
+
+/**
+ * Sample code showing how to use the different API used to achieve a layout rendering.
+ * This requires the following jar: layoutlib_api.jar, common.jar, ide_common.jar, sdklib.jar (altho
+ * we should get rid of this one) and a full SDK (or at leas the platform component).
+ *
+ */
+public class Main {
+
+    // path to the SDK and the project to render
+    private final static String SDK = "...<insert>...";
+    private final static String PROJECT = "...<insert>...";
+
+    /**
+     * @param args
+     */
+    public static void main(String[] args) {
+        // load the factory for a given platform
+        File f = new File(SDK + "/platforms/android-3.1");
+        RenderServiceFactory factory = RenderServiceFactory.create(f);
+
+        if (factory == null) {
+            System.err.println("Failed to load platform rendering library");
+            System.exit(1);
+        }
+
+        // load the project resources
+        ResourceRepository projectRes = new ResourceRepository(false /*isFramework*/) {
+
+            @Override
+            protected ResourceItem createResourceItem(String name) {
+                return new ResourceItem(name);
+            }
+        };
+        try {
+            projectRes.loadResources(new FolderWrapper(PROJECT + "/res"));
+        } catch (IOException e) {
+            e.printStackTrace();
+            System.exit(1);
+        }
+
+        // create the rendering config
+        FolderConfiguration config = RenderServiceFactory.createConfig(
+                1280, 800, // size 1 and 2. order doesn't matter.
+                           // Orientation will drive which is w and h
+                ScreenSize.XLARGE,
+                ScreenRatio.LONG,
+                ScreenOrientation.LANDSCAPE,
+                Density.MEDIUM,
+                TouchScreen.FINGER,
+                KeyboardState.SOFT,
+                Keyboard.QWERTY,
+                NavigationState.EXPOSED,
+                Navigation.NONAV,
+                12); // api level
+
+        // create the resource resolver once for the given config.
+        ResourceResolver resources = factory.createResourceResolver(
+                config, projectRes,
+                "Theme", false /*isProjectTheme*/);
+
+        // create the render service
+        RenderService renderService = factory.createService(
+                resources, config, new ProjectCallback());
+
+        try {
+            RenderSession session = renderService
+                    .setLog(new StdOutLogger())
+                    .setAppInfo("foo", "icon") // optional
+                    .createRenderSession("main" /*layoutName*/);
+
+            // get the status of the render
+            Result result = session.getResult();
+            if (result.isSuccess() == false) {
+                System.err.println(result.getErrorMessage());
+                System.exit(1);
+            }
+
+            // get the image and save it somewhere.
+            BufferedImage image = session.getImage();
+            ImageIO.write(image, "png", new File("/path/to/test.png"));
+
+            // read the views
+            displayViewObjects(session.getRootViews());
+
+            return;
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        } catch (XmlPullParserException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+
+        System.exit(1);
+    }
+
+    private static void displayViewObjects(List<ViewInfo> rootViews) {
+        for (ViewInfo info : rootViews) {
+            displayView(info, "");
+        }
+    }
+
+    private static void displayView(ViewInfo info, String indent) {
+        // display info data
+        System.out.println(indent + info.getClassName() +
+                " [" + info.getLeft() + ", " + info.getTop() + ", " +
+                info.getRight() + ", " + info.getBottom() + "]");
+
+        // display the children
+        List<ViewInfo> children = info.getChildren();
+        if (children != null) {
+            indent += "\t";
+            for (ViewInfo child : children) {
+                displayView(child, indent);
+            }
+        }
+    }
+}
diff --git a/layoutlib_api/sample/src/com/example/android/render/ProjectCallback.java b/layoutlib_api/sample/src/com/example/android/render/ProjectCallback.java
new file mode 100644
index 0000000..2e20f7c
--- /dev/null
+++ b/layoutlib_api/sample/src/com/example/android/render/ProjectCallback.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2011 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.example.android.render;
+
+import com.android.ide.common.rendering.api.AdapterBinding;
+import com.android.ide.common.rendering.api.ILayoutPullParser;
+import com.android.ide.common.rendering.api.IProjectCallback;
+import com.android.ide.common.rendering.api.ResourceReference;
+import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.resources.ResourceType;
+import com.android.util.Pair;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Simple implementation of {@link IProjectCallback}. This is a very basic implementation that
+ * cannot support custom classes. Look for the one in ADT for custom class support.
+ *
+ * Because there's no custom view support, the int to resource name is all dynamic instad of
+ * looking up in the R.java class that was compiled.
+ *
+ */
+public class ProjectCallback implements IProjectCallback {
+
+    private Map<ResourceType, Map<String, Integer>> mIdMap =
+            new HashMap<ResourceType, Map<String, Integer>>();
+    private Map<Integer, Pair<ResourceType, String>> mReverseIdMap =
+            new HashMap<Integer, Pair<ResourceType,String>>();
+
+    public ProjectCallback() {
+
+    }
+
+    public AdapterBinding getAdapterBinding(ResourceReference adapterViewRef, Object adapterCookie,
+            Object viewObject) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public Object getAdapterItemValue(ResourceReference adapterView, Object adapterCookie,
+            ResourceReference itemRef, int fullPosition, int positionPerType,
+            int fullParentPosition, int parentPositionPerType, ResourceReference viewRef,
+            ViewAttribute viewAttribute, Object defaultValue) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    public String getNamespace() {
+        // no custom class == no custom attribute, this is not needed.
+        return null;
+    }
+
+    public ILayoutPullParser getParser(String layoutName) {
+        // don't support custom parser for included files.
+        return null;
+    }
+
+    public ILayoutPullParser getParser(ResourceValue layoutResource) {
+        // don't support custom parser for included files.
+        return null;
+    }
+
+    public Integer getResourceId(ResourceType type, String name) {
+        // since we don't have access to compiled id, generate one on the fly.
+        Map<String, Integer> typeMap = mIdMap.get(type);
+        if (typeMap == null) {
+            typeMap = new HashMap<String, Integer>();
+            mIdMap.put(type, typeMap);
+        }
+
+        Integer value = typeMap.get(name);
+        if (value == null) {
+            value = typeMap.size() + 1;
+            typeMap.put(name, value);
+            mReverseIdMap.put(value, Pair.of(type, name));
+        }
+
+        return value;
+    }
+
+    @SuppressWarnings("unchecked")
+    public Object loadView(String name, Class[] constructorSignature, Object[] constructorArgs)
+            throws ClassNotFoundException, Exception {
+        // don't support custom views.
+        return null;
+    }
+
+    public Pair<ResourceType, String> resolveResourceId(int id) {
+        return mReverseIdMap.get(id);
+    }
+
+    public String resolveResourceId(int[] id) {
+        // this is needed only when custom views have custom styleable
+        return null;
+    }
+
+}
diff --git a/layoutlib_api/sample/src/com/example/android/render/RenderService.java b/layoutlib_api/sample/src/com/example/android/render/RenderService.java
new file mode 100644
index 0000000..33ed35f
--- /dev/null
+++ b/layoutlib_api/sample/src/com/example/android/render/RenderService.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2011 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.example.android.render;
+
+import com.android.ide.common.rendering.LayoutLibrary;
+import com.android.ide.common.rendering.api.DrawableParams;
+import com.android.ide.common.rendering.api.IImageFactory;
+import com.android.ide.common.rendering.api.ILayoutPullParser;
+import com.android.ide.common.rendering.api.IProjectCallback;
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.ide.common.rendering.api.RenderSession;
+import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.ide.common.rendering.api.Result;
+import com.android.ide.common.rendering.api.SessionParams;
+import com.android.ide.common.rendering.api.SessionParams.RenderingMode;
+import com.android.ide.common.resources.ResourceResolver;
+import com.android.ide.common.resources.configuration.FolderConfiguration;
+import com.android.resources.ResourceType;
+import com.android.resources.ScreenOrientation;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+
+
+/**
+ * The {@link RenderService} provides rendering service and easy config.
+ */
+public class RenderService {
+
+    // The following fields are set through the constructor and are required.
+
+    private final IProjectCallback mProjectCallback;
+    private final ResourceResolver mResourceResolver;
+    private final LayoutLibrary mLayoutLib;
+    private final FolderConfiguration mConfig;
+
+    // The following fields are optional or configurable using the various chained
+    // setters:
+
+    private int mWidth;
+    private int mHeight;
+    private int mMinSdkVersion = -1;
+    private int mTargetSdkVersion = -1;
+    private float mXdpi = -1;
+    private float mYdpi = -1;
+    private RenderingMode mRenderingMode = RenderingMode.NORMAL;
+    private LayoutLog mLogger;
+    private Integer mOverrideBgColor;
+    private boolean mShowDecorations = true;
+    private String mAppLabel;
+    private String mAppIconName;
+    private IImageFactory mImageFactory;
+
+    /** Use the {@link RenderServiceFactory#create} factory instead */
+    RenderService(LayoutLibrary layoutLibrary,
+            ResourceResolver resources,
+            FolderConfiguration config,
+            IProjectCallback projectCallback) {
+        mLayoutLib = layoutLibrary;
+        mResourceResolver = resources;
+        mConfig = config;
+        mProjectCallback = projectCallback;
+    }
+
+    /**
+     * Sets the {@link LayoutLog} to be used during rendering. If none is specified, a
+     * silent logger will be used.
+     *
+     * @param logger the log to be used
+     * @return this (such that chains of setters can be stringed together)
+     */
+    public RenderService setLog(LayoutLog logger) {
+        mLogger = logger;
+        return this;
+    }
+
+    /**
+     * Sets the {@link RenderingMode} to be used during rendering. If none is specified,
+     * the default is {@link RenderingMode#NORMAL}.
+     *
+     * @param renderingMode the rendering mode to be used
+     * @return this (such that chains of setters can be stringed together)
+     */
+    public RenderService setRenderingMode(RenderingMode renderingMode) {
+        mRenderingMode = renderingMode;
+        return this;
+    }
+
+    /**
+     * Sets the overriding background color to be used, if any. The color should be a
+     * bitmask of AARRGGBB. The default is null.
+     *
+     * @param overrideBgColor the overriding background color to be used in the rendering,
+     *            in the form of a AARRGGBB bitmask, or null to use no custom background.
+     * @return this (such that chains of setters can be stringed together)
+     */
+    public RenderService setOverrideBgColor(Integer overrideBgColor) {
+        mOverrideBgColor = overrideBgColor;
+        return this;
+    }
+
+    /**
+     * Sets whether the rendering should include decorations such as a system bar, an
+     * application bar etc depending on the SDK target and theme. The default is true.
+     *
+     * @param showDecorations true if the rendering should include system bars etc.
+     * @return this (such that chains of setters can be stringed together)
+     */
+    public RenderService setDecorations(boolean showDecorations) {
+        mShowDecorations = showDecorations;
+        return this;
+    }
+
+    public RenderService setAppInfo(String label, String icon) {
+        mAppLabel = label;
+        mAppIconName = icon;
+        return this;
+    }
+
+    public RenderService setMinSdkVersion(int minSdkVersion) {
+        mMinSdkVersion = minSdkVersion;
+        return this;
+    }
+
+    public RenderService setTargetSdkVersion(int targetSdkVersion) {
+        mTargetSdkVersion = targetSdkVersion;
+        return this;
+    }
+
+    public RenderService setExactDeviceDpi(float xdpi, float ydpi) {
+        mXdpi = xdpi;
+        mYdpi = ydpi;
+        return this;
+    }
+
+    public RenderService setImageFactory(IImageFactory imageFactory) {
+        mImageFactory = imageFactory;
+        return this;
+    }
+
+    /** Initializes any remaining optional fields after all setters have been called */
+    private void finishConfiguration() {
+        if (mLogger == null) {
+            // Silent logging
+            mLogger = new LayoutLog();
+        }
+    }
+
+    /**
+     * Renders the model and returns the result as a {@link RenderSession}.
+     * @return the {@link RenderSession} resulting from rendering the current model
+     * @throws XmlPullParserException
+     * @throws FileNotFoundException
+     */
+    public RenderSession createRenderSession(String layoutName) throws FileNotFoundException,
+            XmlPullParserException {
+        finishConfiguration();
+
+        if (mResourceResolver == null) {
+            // Abort the rendering if the resources are not found.
+            return null;
+        }
+
+        // find the layout to run
+        ResourceValue value = mResourceResolver.getProjectResource(ResourceType.LAYOUT, layoutName);
+        if (value == null || value.getValue() == null) {
+            throw new IllegalArgumentException("layout does not exist");
+        }
+
+        File layoutFile = new File(value.getValue());
+
+        ILayoutPullParser parser = null;
+        parser = new XmlParser();
+        parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
+        parser.setInput(new FileInputStream(layoutFile), "UTF-8"); //$NON-NLS-1$
+
+        figureSomeValuesOut();
+
+        SessionParams params = new SessionParams(
+                parser,
+                mRenderingMode,
+                this /* projectKey */,
+                mWidth, mHeight,
+                mConfig.getDensityQualifier().getValue(),
+                mXdpi, mYdpi,
+                mResourceResolver,
+                mProjectCallback,
+                mMinSdkVersion,
+                mTargetSdkVersion,
+                mLogger);
+
+        // Request margin and baseline information.
+        // TODO: Be smarter about setting this; start without it, and on the first request
+        // for an extended view info, re-render in the same session, and then set a flag
+        // which will cause this to create extended view info each time from then on in the
+        // same session
+        params.setExtendedViewInfoMode(true);
+
+        if (!mShowDecorations) {
+            params.setForceNoDecor();
+        } else {
+            if (mAppLabel == null) {
+                mAppLabel = "Random App";
+            }
+
+            params.setAppLabel(mAppLabel);
+            params.setAppIcon(mAppIconName); // ok to be null
+        }
+
+        params.setConfigScreenSize(mConfig.getScreenSizeQualifier().getValue());
+
+        if (mOverrideBgColor != null) {
+            params.setOverrideBgColor(mOverrideBgColor.intValue());
+        }
+
+        // set the Image Overlay as the image factory.
+        params.setImageFactory(mImageFactory);
+
+        try {
+            return mLayoutLib.createSession(params);
+        } catch (RuntimeException t) {
+            // Exceptions from the bridge
+            mLogger.error(null, t.getLocalizedMessage(), t, null);
+            throw t;
+        }
+    }
+
+    private void figureSomeValuesOut() {
+        int size1 = mConfig.getScreenDimensionQualifier().getValue1();
+        int size2 = mConfig.getScreenDimensionQualifier().getValue2();
+        ScreenOrientation orientation = mConfig.getScreenOrientationQualifier().getValue();
+        switch (orientation) {
+            case LANDSCAPE:
+                mWidth = size1 < size2 ? size2 : size1;
+                mHeight = size1 < size2 ? size1 : size2;
+                break;
+            case PORTRAIT:
+                mWidth = size1 < size2 ? size1 : size2;
+                mHeight = size1 < size2 ? size2 : size1;
+                break;
+            case SQUARE:
+                mWidth = mHeight = size1;
+                break;
+        }
+
+        if (mMinSdkVersion == -1) {
+            mMinSdkVersion = mConfig.getVersionQualifier().getVersion();
+        }
+
+        if (mTargetSdkVersion == -1) {
+            mTargetSdkVersion = mConfig.getVersionQualifier().getVersion();
+        }
+
+        if (mXdpi == -1) {
+            mXdpi = mConfig.getDensityQualifier().getValue().getDpiValue();
+        }
+
+        if (mYdpi == -1) {
+            mYdpi = mConfig.getDensityQualifier().getValue().getDpiValue();
+        }
+    }
+
+    /**
+     * Renders the given resource value (which should refer to a drawable) and returns it
+     * as an image
+     *
+     * @param drawableResourceValue the drawable resource value to be rendered, or null
+     * @return the image, or null if something went wrong
+     */
+    public BufferedImage renderDrawable(ResourceValue drawableResourceValue) {
+        if (drawableResourceValue == null) {
+            return null;
+        }
+
+        finishConfiguration();
+
+        figureSomeValuesOut();
+
+        DrawableParams params = new DrawableParams(drawableResourceValue, this, mWidth, mHeight,
+                mConfig.getDensityQualifier().getValue(),
+                mXdpi, mYdpi, mResourceResolver, mProjectCallback, mMinSdkVersion,
+                mTargetSdkVersion, mLogger);
+        params.setForceNoDecor();
+        Result result = mLayoutLib.renderDrawable(params);
+        if (result != null && result.isSuccess()) {
+            Object data = result.getData();
+            if (data instanceof BufferedImage) {
+                return (BufferedImage) data;
+            }
+        }
+
+        return null;
+    }
+}
diff --git a/layoutlib_api/sample/src/com/example/android/render/RenderServiceFactory.java b/layoutlib_api/sample/src/com/example/android/render/RenderServiceFactory.java
new file mode 100644
index 0000000..dffd4ec
--- /dev/null
+++ b/layoutlib_api/sample/src/com/example/android/render/RenderServiceFactory.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2011 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.example.android.render;
+
+import com.android.ide.common.log.ILogger;
+import com.android.ide.common.rendering.LayoutLibrary;
+import com.android.ide.common.rendering.api.DeclareStyleableResourceValue;
+import com.android.ide.common.rendering.api.IProjectCallback;
+import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.ide.common.resources.FrameworkResources;
+import com.android.ide.common.resources.ResourceItem;
+import com.android.ide.common.resources.ResourceRepository;
+import com.android.ide.common.resources.ResourceResolver;
+import com.android.ide.common.resources.configuration.DensityQualifier;
+import com.android.ide.common.resources.configuration.FolderConfiguration;
+import com.android.ide.common.resources.configuration.KeyboardStateQualifier;
+import com.android.ide.common.resources.configuration.NavigationMethodQualifier;
+import com.android.ide.common.resources.configuration.NavigationStateQualifier;
+import com.android.ide.common.resources.configuration.ScreenDimensionQualifier;
+import com.android.ide.common.resources.configuration.ScreenHeightQualifier;
+import com.android.ide.common.resources.configuration.ScreenOrientationQualifier;
+import com.android.ide.common.resources.configuration.ScreenRatioQualifier;
+import com.android.ide.common.resources.configuration.ScreenSizeQualifier;
+import com.android.ide.common.resources.configuration.ScreenWidthQualifier;
+import com.android.ide.common.resources.configuration.SmallestScreenWidthQualifier;
+import com.android.ide.common.resources.configuration.TextInputMethodQualifier;
+import com.android.ide.common.resources.configuration.TouchScreenQualifier;
+import com.android.ide.common.resources.configuration.VersionQualifier;
+import com.android.ide.common.sdk.LoadStatus;
+import com.android.io.FileWrapper;
+import com.android.io.FolderWrapper;
+import com.android.resources.Density;
+import com.android.resources.Keyboard;
+import com.android.resources.KeyboardState;
+import com.android.resources.Navigation;
+import com.android.resources.NavigationState;
+import com.android.resources.ResourceType;
+import com.android.resources.ScreenOrientation;
+import com.android.resources.ScreenRatio;
+import com.android.resources.ScreenSize;
+import com.android.resources.TouchScreen;
+import com.android.sdklib.SdkConstants;
+import com.android.sdklib.internal.project.ProjectProperties;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * RenderService Factory. This is initialized for a given platform from the SDK.
+ *
+ * Also contains some utility method to create {@link FolderConfiguration} and
+ * {@link ResourceResolver}
+ *
+ */
+public class RenderServiceFactory {
+
+    private LayoutLibrary mLibrary;
+    private FrameworkResources mResources;
+
+    public static RenderServiceFactory create(File platformFolder) {
+
+        // create the factory
+        RenderServiceFactory factory = new RenderServiceFactory();
+        if (factory.loadLibrary(platformFolder)) {
+            return factory;
+        }
+
+        return null;
+    }
+
+    /**
+     * Creates a config. This must be a valid config like a device would return. This is to
+     * prevent issues where some resources don't exist in all cases and not in the default
+     * (for instance only available in hdpi and mdpi but not in default).
+     *
+     * @param size1
+     * @param size2
+     * @param screenSize
+     * @param screenRatio
+     * @param orientation
+     * @param density
+     * @param touchScreen
+     * @param keyboardState
+     * @param keyboard
+     * @param navigationState
+     * @param navigation
+     * @param apiLevel
+     * @return
+     */
+    public static FolderConfiguration createConfig(
+            int size1,
+            int size2,
+            ScreenSize screenSize,
+            ScreenRatio screenRatio,
+            ScreenOrientation orientation,
+            Density density,
+            TouchScreen touchScreen,
+            KeyboardState keyboardState,
+            Keyboard keyboard,
+            NavigationState navigationState,
+            Navigation navigation,
+            int apiLevel) {
+        FolderConfiguration config = new FolderConfiguration();
+
+        int width = size1, height = size2;
+        switch (orientation) {
+            case LANDSCAPE:
+                width = size1 < size2 ? size2 : size1;
+                height = size1 < size2 ? size1 : size2;
+                break;
+            case PORTRAIT:
+                width = size1 < size2 ? size1 : size2;
+                height = size1 < size2 ? size2 : size1;
+                break;
+            case SQUARE:
+                width = height = size1;
+                break;
+        }
+
+        int wdp = (width * Density.DEFAULT_DENSITY) / density.getDpiValue();
+        int hdp = (height * Density.DEFAULT_DENSITY) / density.getDpiValue();
+
+        config.addQualifier(new SmallestScreenWidthQualifier(wdp < hdp ? wdp : hdp));
+        config.addQualifier(new ScreenWidthQualifier(wdp));
+        config.addQualifier(new ScreenHeightQualifier(hdp));
+
+        config.addQualifier(new ScreenSizeQualifier(screenSize));
+        config.addQualifier(new ScreenRatioQualifier(screenRatio));
+        config.addQualifier(new ScreenOrientationQualifier(orientation));
+        config.addQualifier(new DensityQualifier(density));
+        config.addQualifier(new TouchScreenQualifier(touchScreen));
+        config.addQualifier(new KeyboardStateQualifier(keyboardState));
+        config.addQualifier(new TextInputMethodQualifier(keyboard));
+        config.addQualifier(new NavigationStateQualifier(navigationState));
+        config.addQualifier(new NavigationMethodQualifier(navigation));
+        config.addQualifier(width > height ? new ScreenDimensionQualifier(width, height) :
+            new ScreenDimensionQualifier(height, width));
+        config.addQualifier(new VersionQualifier(apiLevel));
+
+        config.updateScreenWidthAndHeight();
+
+        return config;
+    }
+
+    /**
+     * Returns a {@link ResourceResolver} for a given config and project resource.
+     *
+     * @param config
+     * @param projectResources
+     * @param themeName
+     * @param isProjectTheme
+     * @return
+     */
+    public ResourceResolver createResourceResolver(
+            FolderConfiguration config,
+            ResourceRepository projectResources,
+            String themeName,
+            boolean isProjectTheme) {
+
+        Map<ResourceType, Map<String, ResourceValue>> configedProjectRes =
+                projectResources.getConfiguredResources(config);
+
+        Map<ResourceType, Map<String, ResourceValue>> configedFrameworkRes =
+                mResources.getConfiguredResources(config);
+
+        return ResourceResolver.create(configedProjectRes, configedFrameworkRes,
+                themeName, isProjectTheme);
+    }
+
+    /**
+     * Creates a RenderService
+     *
+     * @param resources
+     * @param config
+     * @param projectCallback
+     * @return
+     */
+    public RenderService createService(
+            ResourceResolver resources,
+            FolderConfiguration config,
+            IProjectCallback projectCallback) {
+        RenderService renderService = new RenderService(
+                mLibrary, resources, config, projectCallback);
+
+        return renderService;
+
+    }
+
+    /**
+     * Creates a RenderService. This is less efficient than
+     * {@link #createService(ResourceResolver, FolderConfiguration, IProjectCallback)} since the
+     * {@link ResourceResolver} object is not cached by the caller.
+     *
+     * @param projectResources
+     * @param themeName
+     * @param isProjectTheme
+     * @param config
+     * @param projectCallback
+     * @return
+     */
+    public RenderService createService(
+            ResourceRepository projectResources,
+            String themeName,
+            boolean isProjectTheme,
+            FolderConfiguration config,
+            IProjectCallback projectCallback) {
+        ResourceResolver resources = createResourceResolver(
+                config, projectResources, themeName, isProjectTheme);
+
+        RenderService renderService = new RenderService(
+                mLibrary, resources, config, projectCallback);
+
+        return renderService;
+    }
+
+    private RenderServiceFactory() {
+
+    }
+
+    private boolean loadLibrary(File platformFolder) {
+        if (platformFolder.isDirectory() == false) {
+            throw new IllegalArgumentException("platform folder does not exist.");
+        }
+
+        File dataFolder = new File(platformFolder, "data");
+        if (dataFolder.isDirectory() == false) {
+            throw new IllegalArgumentException("platform data folder does not exist.");
+        }
+
+        File layoutLibJar = new File(dataFolder, "layoutlib.jar");
+        if (layoutLibJar.isFile() == false) {
+            throw new IllegalArgumentException("platform layoutlib.jar does not exist.");
+        }
+
+        File resFolder = new File(dataFolder, "res");
+        if (resFolder.isDirectory() == false) {
+            throw new IllegalArgumentException("platform res folder does not exist.");
+        }
+
+        File fontFolder = new File(dataFolder, "fonts");
+        if (fontFolder.isDirectory() == false) {
+            throw new IllegalArgumentException("platform font folder does not exist.");
+        }
+
+        FileWrapper buildProp = new FileWrapper(platformFolder, SdkConstants.FN_BUILD_PROP);
+        if (buildProp.isFile() == false) {
+            throw new IllegalArgumentException("platform build.prop does not exist.");
+        }
+
+        StdOutLogger log = new StdOutLogger();
+
+        mLibrary = LayoutLibrary.load(layoutLibJar.getAbsolutePath(), log,
+                "LayoutLibRenderer");
+        if (mLibrary.getStatus() != LoadStatus.LOADED) {
+            throw new IllegalArgumentException(mLibrary.getLoadMessage());
+        }
+
+        // load the framework resources
+        mResources = loadResources(resFolder, log);
+
+        // need to get the styleable info to find the enum/flag map.
+        List<ResourceItem> items = mResources.getResourceItemsOfType(
+                ResourceType.DECLARE_STYLEABLE);
+
+        HashMap<String, Map<String, Integer>> enumMap = new HashMap<String, Map<String, Integer>>();
+
+        // standard default config.
+        FolderConfiguration config = new FolderConfiguration();
+        for (ResourceItem item : items) {
+            ResourceValue value = item.getResourceValue(
+                    ResourceType.DECLARE_STYLEABLE, config, true /*isFramework*/);
+            if (value instanceof DeclareStyleableResourceValue) {
+                DeclareStyleableResourceValue styleable = (DeclareStyleableResourceValue) value;
+                Map<String, Map<String, Integer>> map = styleable.getAllAttributes();
+                if (map != null) {
+                    enumMap.putAll(map);
+                }
+            }
+        }
+
+        // we need to parse the build.prop for this
+        Map<String, String> buildPropMap = ProjectProperties.parsePropertyFile(buildProp, log);
+
+        return mLibrary.init(buildPropMap, fontFolder, enumMap, log);
+    }
+
+    private FrameworkResources loadResources(File resFolder, ILogger log) {
+        FrameworkResources resources = new FrameworkResources();
+
+        try {
+            FolderWrapper path = new FolderWrapper(resFolder);
+            resources.loadResources(path);
+            resources.loadPublicResources(path, log);
+            return resources;
+        } catch (IOException e) {
+            // since we test that folders are folders, and files are files, this shouldn't
+            // happen. We can ignore it.
+        }
+
+        return null;
+    }
+
+}
diff --git a/layoutlib_api/sample/src/com/example/android/render/StdOutLogger.java b/layoutlib_api/sample/src/com/example/android/render/StdOutLogger.java
new file mode 100644
index 0000000..e934a2f
--- /dev/null
+++ b/layoutlib_api/sample/src/com/example/android/render/StdOutLogger.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2011 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.example.android.render;
+
+import com.android.ide.common.log.ILogger;
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.sdklib.ISdkLog;
+
+/**
+ * Class implementing the 3 different log interface we use!
+ *
+ * At least ILogger and ISdkLog are identical...
+ *
+ */
+public class StdOutLogger extends LayoutLog implements ILogger, ISdkLog {
+
+    // LayoutLog
+
+    @Override
+    public void error(String tag, String message, Object data) {
+        if (tag != null) {
+            System.err.println("ERROR: [" + tag + "] " +  message);
+        } else {
+            System.err.println("ERROR: " +  message);
+        }
+    }
+
+    @Override
+    public void error(String tag, String message, Throwable throwable, Object data) {
+        error(tag, message, data);
+        throwable.printStackTrace();
+    }
+
+    @Override
+    public void fidelityWarning(String tag, String message, Throwable throwable, Object data) {
+        if (tag != null) {
+            System.out.println("warning: [" + tag + "] " +  message);
+        } else {
+            System.out.println("warning: " +  message);
+        }
+        if (throwable != null) {
+            throwable.printStackTrace();
+        }
+    }
+
+    @Override
+    public void warning(String tag, String message, Object data) {
+        fidelityWarning(tag, message, null /*throwable*/, data);
+    }
+
+    // ILogger / ISdkLog
+
+    public void error(Throwable t, String errorFormat, Object... args) {
+        error(null /*tag*/, String.format(errorFormat, args), t, null /*data*/);
+    }
+
+    public void printf(String msgFormat, Object... args) {
+        System.out.println(String.format(msgFormat, args));
+    }
+
+    public void warning(String warningFormat, Object... args) {
+        warning(null /*tag*/, String.format(warningFormat, args), null /*data*/);
+    }
+}
diff --git a/layoutlib_api/sample/src/com/example/android/render/XmlParser.java b/layoutlib_api/sample/src/com/example/android/render/XmlParser.java
new file mode 100644
index 0000000..6c1f67c
--- /dev/null
+++ b/layoutlib_api/sample/src/com/example/android/render/XmlParser.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2011 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.example.android.render;
+
+import com.android.ide.common.rendering.api.ILayoutPullParser;
+import com.android.ide.common.rendering.api.IProjectCallback;
+
+import org.kxml2.io.KXmlParser;
+
+/**
+ * KXml-based parser that implements {@link ILayoutPullParser}.
+ *
+ */
+public class XmlParser extends KXmlParser implements ILayoutPullParser {
+
+    /**
+     * @deprecated {@link IProjectCallback} replaces this.
+     */
+    @Deprecated
+    public ILayoutPullParser getParser(String layoutName) {
+        return null;
+    }
+
+    public Object getViewCookie() {
+        return null;
+    }
+}
diff --git a/layoutlib_api/sample/testproject/AndroidManifest.xml b/layoutlib_api/sample/testproject/AndroidManifest.xml
new file mode 100644
index 0000000..e584b3c
--- /dev/null
+++ b/layoutlib_api/sample/testproject/AndroidManifest.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+      package="com.example.layoutlib.testproject"
+      android:versionCode="1"
+      android:versionName="1.0">
+    <application android:label="@string/app_name" android:icon="@drawable/icon">
+        <activity android:name="Main"
+                  android:label="@string/app_name">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/layoutlib_api/sample/testproject/build.properties b/layoutlib_api/sample/testproject/build.properties
new file mode 100644
index 0000000..ee52d86
--- /dev/null
+++ b/layoutlib_api/sample/testproject/build.properties
@@ -0,0 +1,17 @@
+# This file is used to override default values used by the Ant build system.
+#
+# This file must be checked in Version Control Systems, as it is
+# integral to the build system of your project.
+
+# This file is only used by the Ant script.
+
+# You can use this to override default values such as
+#  'source.dir' for the location of your java source folder and
+#  'out.dir' for the location of your output folder.
+
+# You can also use it define how the release builds are signed by declaring
+# the following properties:
+#  'key.store' for the location of your keystore and
+#  'key.alias' for the name of the key to use.
+# The password will be asked during the build when you use the 'release' target.
+
diff --git a/layoutlib_api/sample/testproject/build.xml b/layoutlib_api/sample/testproject/build.xml
new file mode 100644
index 0000000..ed79018
--- /dev/null
+++ b/layoutlib_api/sample/testproject/build.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="testproject" default="help">
+
+<!-- The local.properties file is created and updated by the 'android'
+     tool.
+     It contains the path to the SDK. It should *NOT* be checked into
+     Version Control Systems. -->
+    <property file="local.properties" />
+
+    <!-- The build.properties file can be created by you and is never touched
+         by the 'android' tool. This is the place to change some of the
+         default property values used by the Ant rules.
+         Here are some properties you may want to change/update:
+
+         source.dir
+             The name of the source directory. Default is 'src'.
+         out.dir
+             The name of the output directory. Default is 'bin'.
+
+         Properties related to the SDK location or the project target should
+         be updated using the 'android' tool with the 'update' action.
+
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems.
+
+         -->
+    <property file="build.properties" />
+
+    <!-- The default.properties file is created and updated by the 'android'
+         tool, as well as ADT.
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems. -->
+    <property file="default.properties" />
+
+
+    <!-- Required pre-setup import -->
+    <import file="${sdk.dir}/tools/ant/pre_setup.xml" />
+
+
+<!-- extension targets. Uncomment the ones where you want to do custom work
+     in between standard targets -->
+<!--
+    <target name="-pre-build">
+    </target>
+    <target name="-pre-compile">
+    </target>
+
+    [This is typically used for code obfuscation.
+     Compiled code location: ${out.classes.absolute.dir}
+     If this is not done in place, override ${out.dex.input.absolute.dir}]
+    <target name="-post-compile">
+    </target>
+-->
+
+    <!-- Execute the Android Setup task that will setup some properties
+         specific to the target, and import the build rules files.
+
+         The rules file is imported from
+            <SDK>/tools/ant/
+         Depending on the project type it can be either:
+         - main_rules.xml
+         - lib_rules.xml
+         - test_rules.xml
+
+         To customize existing targets, there are two options:
+         - Customize only one target:
+             - copy/paste the target into this file, *before* the
+               <setup> task.
+             - customize it to your needs.
+         - Customize the whole script.
+             - copy/paste the content of the rules files (minus the top node)
+               into this file, *after* the <setup> task
+             - disable the import of the rules by changing the setup task
+               below to <setup import="false" />.
+             - customize to your needs.
+    -->
+    <setup />
+
+</project>
diff --git a/layoutlib_api/sample/testproject/default.properties b/layoutlib_api/sample/testproject/default.properties
new file mode 100644
index 0000000..8ee25b8
--- /dev/null
+++ b/layoutlib_api/sample/testproject/default.properties
@@ -0,0 +1,11 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system use,
+# "build.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-AOSP
diff --git a/layoutlib_api/sample/testproject/proguard.cfg b/layoutlib_api/sample/testproject/proguard.cfg
new file mode 100644
index 0000000..b1cdf17
--- /dev/null
+++ b/layoutlib_api/sample/testproject/proguard.cfg
@@ -0,0 +1,40 @@
+-optimizationpasses 5
+-dontusemixedcaseclassnames
+-dontskipnonpubliclibraryclasses
+-dontpreverify
+-verbose
+-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
+
+-keep public class * extends android.app.Activity
+-keep public class * extends android.app.Application
+-keep public class * extends android.app.Service
+-keep public class * extends android.content.BroadcastReceiver
+-keep public class * extends android.content.ContentProvider
+-keep public class * extends android.app.backup.BackupAgentHelper
+-keep public class * extends android.preference.Preference
+-keep public class com.android.vending.licensing.ILicensingService
+
+-keepclasseswithmembernames class * {
+    native <methods>;
+}
+
+-keepclasseswithmembers class * {
+    public <init>(android.content.Context, android.util.AttributeSet);
+}
+
+-keepclasseswithmembers class * {
+    public <init>(android.content.Context, android.util.AttributeSet, int);
+}
+
+-keepclassmembers class * extends android.app.Activity {
+   public void *(android.view.View);
+}
+
+-keepclassmembers enum * {
+    public static **[] values();
+    public static ** valueOf(java.lang.String);
+}
+
+-keep class * implements android.os.Parcelable {
+  public static final android.os.Parcelable$Creator *;
+}
diff --git a/layoutlib_api/sample/testproject/res/drawable-hdpi/icon.png b/layoutlib_api/sample/testproject/res/drawable-hdpi/icon.png
new file mode 100644
index 0000000..8074c4c
--- /dev/null
+++ b/layoutlib_api/sample/testproject/res/drawable-hdpi/icon.png
Binary files differ
diff --git a/layoutlib_api/sample/testproject/res/drawable-ldpi/icon.png b/layoutlib_api/sample/testproject/res/drawable-ldpi/icon.png
new file mode 100644
index 0000000..1095584
--- /dev/null
+++ b/layoutlib_api/sample/testproject/res/drawable-ldpi/icon.png
Binary files differ
diff --git a/layoutlib_api/sample/testproject/res/drawable-mdpi/icon.png b/layoutlib_api/sample/testproject/res/drawable-mdpi/icon.png
new file mode 100644
index 0000000..a07c69f
--- /dev/null
+++ b/layoutlib_api/sample/testproject/res/drawable-mdpi/icon.png
Binary files differ
diff --git a/layoutlib_api/sample/testproject/res/layout/main.xml b/layoutlib_api/sample/testproject/res/layout/main.xml
new file mode 100644
index 0000000..b79cddb
--- /dev/null
+++ b/layoutlib_api/sample/testproject/res/layout/main.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    >
+<TextView
+    android:layout_width="fill_parent"
+    android:layout_height="wrap_content"
+    android:text="Hello World, Main"
+    />
+</LinearLayout>
+
diff --git a/layoutlib_api/sample/testproject/res/values/strings.xml b/layoutlib_api/sample/testproject/res/values/strings.xml
new file mode 100644
index 0000000..549e4ea
--- /dev/null
+++ b/layoutlib_api/sample/testproject/res/values/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="app_name">Main</string>
+</resources>
diff --git a/layoutlib_api/sample/testproject/src/com/example/layoutlib/testproject/Main.java b/layoutlib_api/sample/testproject/src/com/example/layoutlib/testproject/Main.java
new file mode 100644
index 0000000..90ec357
--- /dev/null
+++ b/layoutlib_api/sample/testproject/src/com/example/layoutlib/testproject/Main.java
@@ -0,0 +1,15 @@
+package com.example.layoutlib.testproject;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class Main extends Activity
+{
+    /** Called when the activity is first created. */
+    @Override
+    public void onCreate(Bundle savedInstanceState)
+    {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.main);
+    }
+}
diff --git a/layoutlib_api/src/com/android/ide/common/rendering/api/DeclareStyleableResourceValue.java b/layoutlib_api/src/com/android/ide/common/rendering/api/DeclareStyleableResourceValue.java
index 2b13d0b..0699766 100644
--- a/layoutlib_api/src/com/android/ide/common/rendering/api/DeclareStyleableResourceValue.java
+++ b/layoutlib_api/src/com/android/ide/common/rendering/api/DeclareStyleableResourceValue.java
@@ -50,6 +50,10 @@
         return null;
     }
 
+    public Map<String, Map<String, Integer>> getAllAttributes() {
+        return mEnumMap;
+    }
+
     public void addValue(String attribute, String name, Integer value) {
         Map<String, Integer> map;