aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderService.java8
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/resources/manager/ResourceManager.java53
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/tests/functests/layoutRendering/ApiDemosRenderingTest.java7
-rw-r--r--ide_common/src/com/android/ide/common/resources/ResourceRepository.java35
-rw-r--r--layoutlib_api/sample/.classpath11
-rw-r--r--layoutlib_api/sample/.project17
-rw-r--r--layoutlib_api/sample/README.txt16
-rw-r--r--layoutlib_api/sample/src/com/example/android/render/Main.java164
-rw-r--r--layoutlib_api/sample/src/com/example/android/render/ProjectCallback.java112
-rw-r--r--layoutlib_api/sample/src/com/example/android/render/RenderService.java313
-rw-r--r--layoutlib_api/sample/src/com/example/android/render/RenderServiceFactory.java320
-rw-r--r--layoutlib_api/sample/src/com/example/android/render/StdOutLogger.java78
-rw-r--r--layoutlib_api/sample/src/com/example/android/render/XmlParser.java41
-rw-r--r--layoutlib_api/sample/testproject/AndroidManifest.xml15
-rw-r--r--layoutlib_api/sample/testproject/build.properties17
-rw-r--r--layoutlib_api/sample/testproject/build.xml79
-rw-r--r--layoutlib_api/sample/testproject/default.properties11
-rw-r--r--layoutlib_api/sample/testproject/proguard.cfg40
-rw-r--r--layoutlib_api/sample/testproject/res/drawable-hdpi/icon.pngbin0 -> 4147 bytes
-rw-r--r--layoutlib_api/sample/testproject/res/drawable-ldpi/icon.pngbin0 -> 1723 bytes
-rw-r--r--layoutlib_api/sample/testproject/res/drawable-mdpi/icon.pngbin0 -> 2574 bytes
-rw-r--r--layoutlib_api/sample/testproject/res/layout/main.xml13
-rw-r--r--layoutlib_api/sample/testproject/res/values/strings.xml4
-rw-r--r--layoutlib_api/sample/testproject/src/com/example/layoutlib/testproject/Main.java15
-rw-r--r--layoutlib_api/src/com/android/ide/common/rendering/api/DeclareStyleableResourceValue.java4
25 files changed, 1312 insertions, 61 deletions
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.layout.uimodel.UiViewElement
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 @@ public class RenderService {
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.internal.resources.manager.GlobalProjectMonit
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.resources.IResourceDelta;
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 @@ public final class ResourceManager {
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 @@ public final class ResourceManager {
}
/**
- * 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.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;
@@ -51,6 +52,7 @@ 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;
@@ -204,7 +206,7 @@ public class ApiDemosRenderingTest extends SdkTestCase {
// 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 @@ public class ApiDemosRenderingTest extends SdkTestCase {
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.Configurable;
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 @@ public abstract class ResourceRepository {
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 @@ public class DeclareStyleableResourceValue extends ResourceValue {
return null;
}
+ public Map<String, Map<String, Integer>> getAllAttributes() {
+ return mEnumMap;
+ }
+
public void addValue(String attribute, String name, Integer value) {
Map<String, Integer> map;