diff options
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 Binary files differnew file mode 100644 index 0000000..8074c4c --- /dev/null +++ b/layoutlib_api/sample/testproject/res/drawable-hdpi/icon.png diff --git a/layoutlib_api/sample/testproject/res/drawable-ldpi/icon.png b/layoutlib_api/sample/testproject/res/drawable-ldpi/icon.png Binary files differnew file mode 100644 index 0000000..1095584 --- /dev/null +++ b/layoutlib_api/sample/testproject/res/drawable-ldpi/icon.png diff --git a/layoutlib_api/sample/testproject/res/drawable-mdpi/icon.png b/layoutlib_api/sample/testproject/res/drawable-mdpi/icon.png Binary files differnew file mode 100644 index 0000000..a07c69f --- /dev/null +++ b/layoutlib_api/sample/testproject/res/drawable-mdpi/icon.png 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; |