aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderService.java
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderService.java')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderService.java668
1 files changed, 668 insertions, 0 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
new file mode 100644
index 000000000..3b9e2fc0f
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderService.java
@@ -0,0 +1,668 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
+ *
+ * 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.android.ide.eclipse.adt.internal.editors.layout.gle2;
+
+import static com.android.SdkConstants.LAYOUT_RESOURCE_PREFIX;
+
+import com.android.annotations.NonNull;
+import com.android.ide.common.api.IClientRulesEngine;
+import com.android.ide.common.api.INode;
+import com.android.ide.common.api.Rect;
+import com.android.ide.common.rendering.HardwareConfigHelper;
+import com.android.ide.common.rendering.LayoutLibrary;
+import com.android.ide.common.rendering.RenderSecurityManager;
+import com.android.ide.common.rendering.api.AssetRepository;
+import com.android.ide.common.rendering.api.Capability;
+import com.android.ide.common.rendering.api.DrawableParams;
+import com.android.ide.common.rendering.api.HardwareConfig;
+import com.android.ide.common.rendering.api.IImageFactory;
+import com.android.ide.common.rendering.api.ILayoutPullParser;
+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.rendering.api.ViewInfo;
+import com.android.ide.common.resources.ResourceResolver;
+import com.android.ide.common.resources.configuration.FolderConfiguration;
+import com.android.ide.eclipse.adt.AdtPlugin;
+import com.android.ide.eclipse.adt.AdtUtils;
+import com.android.ide.eclipse.adt.internal.editors.layout.ContextPullParser;
+import com.android.ide.eclipse.adt.internal.editors.layout.ProjectCallback;
+import com.android.ide.eclipse.adt.internal.editors.layout.UiElementPullParser;
+import com.android.ide.eclipse.adt.internal.editors.layout.configuration.Configuration;
+import com.android.ide.eclipse.adt.internal.editors.layout.configuration.ConfigurationChooser;
+import com.android.ide.eclipse.adt.internal.editors.layout.configuration.Locale;
+import com.android.ide.eclipse.adt.internal.editors.layout.gle2.IncludeFinder.Reference;
+import com.android.ide.eclipse.adt.internal.editors.layout.gre.NodeFactory;
+import com.android.ide.eclipse.adt.internal.editors.layout.gre.NodeProxy;
+import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode;
+import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo;
+import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestInfo.ActivityAttributes;
+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.sdk.AndroidTargetData;
+import com.android.ide.eclipse.adt.internal.sdk.Sdk;
+import com.android.sdklib.IAndroidTarget;
+import com.android.sdklib.devices.Device;
+import com.google.common.base.Charsets;
+import com.google.common.io.Files;
+
+import org.eclipse.core.resources.IProject;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.awt.Toolkit;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * The {@link RenderService} provides rendering and layout information for
+ * Android layouts. This is a wrapper around the layout library.
+ */
+public class RenderService {
+ private static final Object RENDERING_LOCK = new Object();
+
+ /** Reference to the file being edited. Can also be used to access the {@link IProject}. */
+ private final GraphicalEditorPart mEditor;
+
+ // The following fields are inferred from the editor and not customizable by the
+ // client of the render service:
+
+ private final IProject mProject;
+ private final ProjectCallback mProjectCallback;
+ private final ResourceResolver mResourceResolver;
+ private final int mMinSdkVersion;
+ private final int mTargetSdkVersion;
+ private final LayoutLibrary mLayoutLib;
+ private final IImageFactory mImageFactory;
+ private final HardwareConfigHelper mHardwareConfigHelper;
+ private final Locale mLocale;
+
+ // The following fields are optional or configurable using the various chained
+ // setters:
+
+ private UiDocumentNode mModel;
+ private Reference mIncludedWithin;
+ private RenderingMode mRenderingMode = RenderingMode.NORMAL;
+ private LayoutLog mLogger;
+ private Integer mOverrideBgColor;
+ private boolean mShowDecorations = true;
+ private Set<UiElementNode> mExpandNodes = Collections.<UiElementNode>emptySet();
+ private final Object mCredential;
+
+ /** Use the {@link #create} factory instead */
+ private RenderService(GraphicalEditorPart editor, Object credential) {
+ mEditor = editor;
+ mCredential = credential;
+
+ mProject = editor.getProject();
+ LayoutCanvas canvas = editor.getCanvasControl();
+ mImageFactory = canvas.getImageOverlay();
+ ConfigurationChooser chooser = editor.getConfigurationChooser();
+ Configuration config = chooser.getConfiguration();
+ FolderConfiguration folderConfig = config.getFullConfig();
+
+ Device device = config.getDevice();
+ assert device != null; // Should only attempt render with configuration that has device
+ mHardwareConfigHelper = new HardwareConfigHelper(device);
+ mHardwareConfigHelper.setOrientation(
+ folderConfig.getScreenOrientationQualifier().getValue());
+
+ mLayoutLib = editor.getReadyLayoutLib(true /*displayError*/);
+ mResourceResolver = editor.getResourceResolver();
+ mProjectCallback = editor.getProjectCallback(true /*reset*/, mLayoutLib);
+ mMinSdkVersion = editor.getMinSdkVersion();
+ mTargetSdkVersion = editor.getTargetSdkVersion();
+ mLocale = config.getLocale();
+ }
+
+ private RenderService(GraphicalEditorPart editor,
+ Configuration configuration, ResourceResolver resourceResolver,
+ Object credential) {
+ mEditor = editor;
+ mCredential = credential;
+
+ mProject = editor.getProject();
+ LayoutCanvas canvas = editor.getCanvasControl();
+ mImageFactory = canvas.getImageOverlay();
+ FolderConfiguration folderConfig = configuration.getFullConfig();
+
+ Device device = configuration.getDevice();
+ assert device != null;
+ mHardwareConfigHelper = new HardwareConfigHelper(device);
+ mHardwareConfigHelper.setOrientation(
+ folderConfig.getScreenOrientationQualifier().getValue());
+
+ mLayoutLib = editor.getReadyLayoutLib(true /*displayError*/);
+ mResourceResolver = resourceResolver != null ? resourceResolver : editor.getResourceResolver();
+ mProjectCallback = editor.getProjectCallback(true /*reset*/, mLayoutLib);
+ mMinSdkVersion = editor.getMinSdkVersion();
+ mTargetSdkVersion = editor.getTargetSdkVersion();
+ mLocale = configuration.getLocale();
+ }
+
+ private RenderSecurityManager createSecurityManager() {
+ String projectPath = null;
+ String sdkPath = null;
+ if (RenderSecurityManager.RESTRICT_READS) {
+ projectPath = AdtUtils.getAbsolutePath(mProject).toFile().getPath();
+ Sdk sdk = Sdk.getCurrent();
+ sdkPath = sdk != null ? sdk.getSdkOsLocation() : null;
+ }
+ RenderSecurityManager securityManager = new RenderSecurityManager(sdkPath, projectPath);
+ securityManager.setLogger(AdtPlugin.getDefault());
+
+ // Make sure this is initialized before we attempt to use it from layoutlib
+ Toolkit.getDefaultToolkit();
+
+ return securityManager;
+ }
+
+ /**
+ * Returns true if this configuration supports the given rendering
+ * capability
+ *
+ * @param target the target to look up the layout library for
+ * @param capability the capability to check
+ * @return true if the capability is supported
+ */
+ public static boolean supports(
+ @NonNull IAndroidTarget target,
+ @NonNull Capability capability) {
+ Sdk sdk = Sdk.getCurrent();
+ if (sdk != null) {
+ AndroidTargetData targetData = sdk.getTargetData(target);
+ if (targetData != null) {
+ LayoutLibrary layoutLib = targetData.getLayoutLibrary();
+ if (layoutLib != null) {
+ return layoutLib.supports(capability);
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Creates a new {@link RenderService} associated with the given editor.
+ *
+ * @param editor the editor to provide configuration data such as the render target
+ * @return a {@link RenderService} which can perform rendering services
+ */
+ public static RenderService create(GraphicalEditorPart editor) {
+ // Delegate to editor such that it can pass its credential to the service
+ return editor.createRenderService();
+ }
+
+ /**
+ * Creates a new {@link RenderService} associated with the given editor.
+ *
+ * @param editor the editor to provide configuration data such as the render target
+ * @param credential the sandbox credential
+ * @return a {@link RenderService} which can perform rendering services
+ */
+ @NonNull
+ public static RenderService create(GraphicalEditorPart editor, Object credential) {
+ return new RenderService(editor, credential);
+ }
+
+ /**
+ * Creates a new {@link RenderService} associated with the given editor.
+ *
+ * @param editor the editor to provide configuration data such as the render target
+ * @param configuration the configuration to use (and fallback to editor for the rest)
+ * @param resolver a resource resolver to use to look up resources
+ * @return a {@link RenderService} which can perform rendering services
+ */
+ public static RenderService create(GraphicalEditorPart editor,
+ Configuration configuration, ResourceResolver resolver) {
+ // Delegate to editor such that it can pass its credential to the service
+ return editor.createRenderService(configuration, resolver);
+ }
+
+ /**
+ * Creates a new {@link RenderService} associated with the given editor.
+ *
+ * @param editor the editor to provide configuration data such as the render target
+ * @param configuration the configuration to use (and fallback to editor for the rest)
+ * @param resolver a resource resolver to use to look up resources
+ * @param credential the sandbox credential
+ * @return a {@link RenderService} which can perform rendering services
+ */
+ public static RenderService create(GraphicalEditorPart editor,
+ Configuration configuration, ResourceResolver resolver, Object credential) {
+ return new RenderService(editor, configuration, resolver, credential);
+ }
+
+ /**
+ * Renders the given model, using this editor's theme and screen settings, and returns
+ * the result as a {@link RenderSession}.
+ *
+ * @param model the model to be rendered, which can be different than the editor's own
+ * {@link #getModel()}.
+ * @param width the width to use for the layout, or -1 to use the width of the screen
+ * associated with this editor
+ * @param height the height to use for the layout, or -1 to use the height of the screen
+ * associated with this editor
+ * @param explodeNodes a set of nodes to explode, or null for none
+ * @param overrideBgColor If non-null, use the given color as a background to render over
+ * rather than the normal background requested by the theme
+ * @param noDecor If true, don't draw window decorations like the system bar
+ * @param logger a logger where rendering errors are reported
+ * @param renderingMode the {@link RenderingMode} to use for rendering
+ * @return the resulting rendered image wrapped in an {@link RenderSession}
+ */
+
+ /**
+ * 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 model to be rendered, which can be different than the editor's own
+ * {@link GraphicalEditorPart#getModel()}.
+ *
+ * @param model the model to be rendered
+ * @return this (such that chains of setters can be stringed together)
+ */
+ public RenderService setModel(UiDocumentNode model) {
+ mModel = model;
+ return this;
+ }
+
+ /**
+ * Overrides the width and height to be used during rendering (which might be adjusted if
+ * the {@link #setRenderingMode(RenderingMode)} is {@link RenderingMode#FULL_EXPAND}.
+ *
+ * A value of -1 will make the rendering use the normal width and height coming from the
+ * {@link Configuration#getDevice()} object.
+ *
+ * @param overrideRenderWidth the width in pixels of the layout to be rendered
+ * @param overrideRenderHeight the height in pixels of the layout to be rendered
+ * @return this (such that chains of setters can be stringed together)
+ */
+ public RenderService setOverrideRenderSize(int overrideRenderWidth, int overrideRenderHeight) {
+ mHardwareConfigHelper.setOverrideRenderSize(overrideRenderWidth, overrideRenderHeight);
+ return this;
+ }
+
+ /**
+ * Sets the max width and height to be used during rendering (which might be adjusted if
+ * the {@link #setRenderingMode(RenderingMode)} is {@link RenderingMode#FULL_EXPAND}.
+ *
+ * A value of -1 will make the rendering use the normal width and height coming from the
+ * {@link Configuration#getDevice()} object.
+ *
+ * @param maxRenderWidth the max width in pixels of the layout to be rendered
+ * @param maxRenderHeight the max height in pixels of the layout to be rendered
+ * @return this (such that chains of setters can be stringed together)
+ */
+ public RenderService setMaxRenderSize(int maxRenderWidth, int maxRenderHeight) {
+ mHardwareConfigHelper.setMaxRenderSize(maxRenderWidth, maxRenderHeight);
+ 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;
+ }
+
+ /**
+ * Sets the nodes to expand during rendering. These will be padded with approximately
+ * 20 pixels and also highlighted by the {@link EmptyViewsOverlay}. The default is an
+ * empty collection.
+ *
+ * @param nodesToExpand the nodes to be expanded
+ * @return this (such that chains of setters can be stringed together)
+ */
+ public RenderService setNodesToExpand(Set<UiElementNode> nodesToExpand) {
+ mExpandNodes = nodesToExpand;
+ return this;
+ }
+
+ /**
+ * Sets the {@link Reference} to an outer layout that this layout should be rendered
+ * within. The outer layout <b>must</b> contain an include tag which points to this
+ * layout. The default is null.
+ *
+ * @param includedWithin a reference to an outer layout to render this layout within
+ * @return this (such that chains of setters can be stringed together)
+ */
+ public RenderService setIncludedWithin(Reference includedWithin) {
+ mIncludedWithin = includedWithin;
+ 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
+ */
+ public RenderSession createRenderSession() {
+ assert mModel != null : "Incomplete service config";
+ finishConfiguration();
+
+ if (mResourceResolver == null) {
+ // Abort the rendering if the resources are not found.
+ return null;
+ }
+
+ HardwareConfig hardwareConfig = mHardwareConfigHelper.getConfig();
+
+ UiElementPullParser modelParser = new UiElementPullParser(mModel,
+ false, mExpandNodes, hardwareConfig.getDensity(), mProject);
+ ILayoutPullParser topParser = modelParser;
+
+ // Code to support editing included layout
+ // first reset the layout parser just in case.
+ mProjectCallback.setLayoutParser(null, null);
+
+ if (mIncludedWithin != null) {
+ // Outer layout name:
+ String contextLayoutName = mIncludedWithin.getName();
+
+ // Find the layout file.
+ ResourceValue contextLayout = mResourceResolver.findResValue(
+ LAYOUT_RESOURCE_PREFIX + contextLayoutName, false /* forceFrameworkOnly*/);
+ if (contextLayout != null) {
+ File layoutFile = new File(contextLayout.getValue());
+ if (layoutFile.isFile()) {
+ try {
+ // Get the name of the layout actually being edited, without the extension
+ // as it's what IXmlPullParser.getParser(String) will receive.
+ String queryLayoutName = mEditor.getLayoutResourceName();
+ mProjectCallback.setLayoutParser(queryLayoutName, modelParser);
+ topParser = new ContextPullParser(mProjectCallback, layoutFile);
+ topParser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
+ String xmlText = Files.toString(layoutFile, Charsets.UTF_8);
+ topParser.setInput(new StringReader(xmlText));
+ } catch (IOException e) {
+ AdtPlugin.log(e, null);
+ } catch (XmlPullParserException e) {
+ AdtPlugin.log(e, null);
+ }
+ }
+ }
+ }
+
+ SessionParams params = new SessionParams(
+ topParser,
+ mRenderingMode,
+ mProject /* projectKey */,
+ hardwareConfig,
+ 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);
+
+ params.setLocale(mLocale.toLocaleId());
+ params.setAssetRepository(new AssetRepository());
+
+ ManifestInfo manifestInfo = ManifestInfo.get(mProject);
+ try {
+ params.setRtlSupport(manifestInfo.isRtlSupported());
+ } catch (Exception e) {
+ // ignore.
+ }
+ if (!mShowDecorations) {
+ params.setForceNoDecor();
+ } else {
+ try {
+ params.setAppLabel(manifestInfo.getApplicationLabel());
+ params.setAppIcon(manifestInfo.getApplicationIcon());
+ String activity = mEditor.getConfigurationChooser().getConfiguration().getActivity();
+ if (activity != null) {
+ ActivityAttributes info = manifestInfo.getActivityAttributes(activity);
+ if (info != null) {
+ if (info.getLabel() != null) {
+ params.setAppLabel(info.getLabel());
+ }
+ if (info.getIcon() != null) {
+ params.setAppIcon(info.getIcon());
+ }
+ }
+ }
+ } catch (Exception e) {
+ // ignore.
+ }
+ }
+
+ if (mOverrideBgColor != null) {
+ params.setOverrideBgColor(mOverrideBgColor.intValue());
+ }
+
+ // set the Image Overlay as the image factory.
+ params.setImageFactory(mImageFactory);
+
+ mProjectCallback.setLogger(mLogger);
+ mProjectCallback.setResourceResolver(mResourceResolver);
+ RenderSecurityManager securityManager = createSecurityManager();
+ try {
+ securityManager.setActive(true, mCredential);
+ synchronized (RENDERING_LOCK) {
+ return mLayoutLib.createSession(params);
+ }
+ } catch (RuntimeException t) {
+ // Exceptions from the bridge
+ mLogger.error(null, t.getLocalizedMessage(), t, null);
+ throw t;
+ } finally {
+ securityManager.dispose(mCredential);
+ mProjectCallback.setLogger(null);
+ mProjectCallback.setResourceResolver(null);
+ }
+ }
+
+ /**
+ * 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();
+
+ HardwareConfig hardwareConfig = mHardwareConfigHelper.getConfig();
+
+ DrawableParams params = new DrawableParams(drawableResourceValue, mProject, hardwareConfig,
+ mResourceResolver, mProjectCallback, mMinSdkVersion,
+ mTargetSdkVersion, mLogger);
+ params.setAssetRepository(new AssetRepository());
+ 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;
+ }
+
+ /**
+ * Measure the children of the given parent node, applying the given filter to the
+ * pull parser's attribute values.
+ *
+ * @param parent the parent node to measure children for
+ * @param filter the filter to apply to the attribute values
+ * @return a map from node children of the parent to new bounds of the nodes
+ */
+ public Map<INode, Rect> measureChildren(INode parent,
+ final IClientRulesEngine.AttributeFilter filter) {
+ finishConfiguration();
+ HardwareConfig hardwareConfig = mHardwareConfigHelper.getConfig();
+
+ final NodeFactory mNodeFactory = mEditor.getCanvasControl().getNodeFactory();
+ UiElementNode parentNode = ((NodeProxy) parent).getNode();
+ UiElementPullParser topParser = new UiElementPullParser(parentNode,
+ false, Collections.<UiElementNode>emptySet(), hardwareConfig.getDensity(),
+ mProject) {
+ @Override
+ public String getAttributeValue(String namespace, String localName) {
+ if (filter != null) {
+ Object cookie = getViewCookie();
+ if (cookie instanceof UiViewElementNode) {
+ NodeProxy node = mNodeFactory.create((UiViewElementNode) cookie);
+ if (node != null) {
+ String value = filter.getAttribute(node, namespace, localName);
+ if (value != null) {
+ return value;
+ }
+ // null means no preference, not "unset".
+ }
+ }
+ }
+
+ return super.getAttributeValue(namespace, localName);
+ }
+
+ /**
+ * The parser usually assumes that the top level node is a document node that
+ * should be skipped, and that's not the case when we render in the middle of
+ * the tree, so override {@link UiElementPullParser#onNextFromStartDocument}
+ * to change this behavior
+ */
+ @Override
+ public void onNextFromStartDocument() {
+ mParsingState = START_TAG;
+ }
+ };
+
+ SessionParams params = new SessionParams(
+ topParser,
+ RenderingMode.FULL_EXPAND,
+ mProject /* projectKey */,
+ hardwareConfig,
+ mResourceResolver,
+ mProjectCallback,
+ mMinSdkVersion,
+ mTargetSdkVersion,
+ mLogger);
+ params.setLayoutOnly();
+ params.setForceNoDecor();
+ params.setAssetRepository(new AssetRepository());
+
+ RenderSession session = null;
+ mProjectCallback.setLogger(mLogger);
+ mProjectCallback.setResourceResolver(mResourceResolver);
+ RenderSecurityManager securityManager = createSecurityManager();
+ try {
+ securityManager.setActive(true, mCredential);
+ synchronized (RENDERING_LOCK) {
+ session = mLayoutLib.createSession(params);
+ }
+ if (session.getResult().isSuccess()) {
+ assert session.getRootViews().size() == 1;
+ ViewInfo root = session.getRootViews().get(0);
+ List<ViewInfo> children = root.getChildren();
+ Map<INode, Rect> map = new HashMap<INode, Rect>(children.size());
+ for (ViewInfo info : children) {
+ if (info.getCookie() instanceof UiViewElementNode) {
+ UiViewElementNode uiNode = (UiViewElementNode) info.getCookie();
+ NodeProxy node = mNodeFactory.create(uiNode);
+ map.put(node, new Rect(info.getLeft(), info.getTop(),
+ info.getRight() - info.getLeft(),
+ info.getBottom() - info.getTop()));
+ }
+ }
+
+ return map;
+ }
+ } catch (RuntimeException t) {
+ // Exceptions from the bridge
+ mLogger.error(null, t.getLocalizedMessage(), t, null);
+ throw t;
+ } finally {
+ securityManager.dispose(mCredential);
+ mProjectCallback.setLogger(null);
+ mProjectCallback.setResourceResolver(null);
+ if (session != null) {
+ session.dispose();
+ }
+ }
+
+ return null;
+ }
+}