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/ContextPullParser.java102
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ProjectCallback.java63
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java6
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutMetadata.java44
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/RenderService.java6
5 files changed, 187 insertions, 34 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ContextPullParser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ContextPullParser.java
index 7c40097..bd1ac81 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ContextPullParser.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ContextPullParser.java
@@ -20,28 +20,45 @@ import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_HEIGHT;
import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_WIDTH;
import static com.android.ide.common.layout.LayoutConstants.VALUE_FILL_PARENT;
import static com.android.ide.common.layout.LayoutConstants.VALUE_MATCH_PARENT;
+import static com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors.ATTR_LAYOUT;
+import static com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors.VIEW_FRAGMENT;
+import static com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors.VIEW_INCLUDE;
+import static com.android.ide.eclipse.adt.internal.editors.layout.gle2.LayoutMetadata.KEY_FRAGMENT_LAYOUT;
import com.android.ide.common.rendering.api.ILayoutPullParser;
import com.android.ide.common.rendering.api.IProjectCallback;
-import com.android.layoutlib.api.IXmlPullParser;
+import com.android.ide.eclipse.adt.AdtPlugin;
+import com.android.ide.eclipse.adt.internal.editors.layout.gle2.LayoutMetadata;
import com.android.sdklib.SdkConstants;
import org.kxml2.io.KXmlParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.File;
/**
- * Modified {@link KXmlParser} that adds the methods of {@link ILayoutPullParser}.
+ * Modified {@link KXmlParser} that adds the methods of {@link ILayoutPullParser}, and
+ * performs other layout-specific parser behavior like translating fragment tags into
+ * include tags.
* <p/>
* It will return a given parser when queried for one through
- * {@link IXmlPullParser#getParser(String)} for a given name.
+ * {@link ILayoutPullParser#getParser(String)} for a given name.
*
*/
public class ContextPullParser extends KXmlParser implements ILayoutPullParser {
-
+ private static final String COMMENT_PREFIX = "<!--"; //$NON-NLS-1$
+ private static final String COMMENT_SUFFIX = "-->"; //$NON-NLS-1$
+ /** The callback to request parsers from */
private final IProjectCallback mProjectCallback;
+ /** The {@link File} for the layout currently being parsed */
+ private File mFile;
+ /** The layout to be shown for the current {@code <fragment>} tag. Usually null. */
+ private String mFragmentLayout = null;
- public ContextPullParser(IProjectCallback projectCallback) {
+ public ContextPullParser(IProjectCallback projectCallback, File file) {
super();
mProjectCallback = projectCallback;
+ mFile = file;
}
// --- Layout lib API methods
@@ -62,7 +79,28 @@ public class ContextPullParser extends KXmlParser implements ILayoutPullParser {
// --- KXMLParser override
@Override
+ public String getName() {
+ String name = super.getName();
+
+ // At designtime, replace fragments with includes.
+ if (name.equals(VIEW_FRAGMENT)) {
+ mFragmentLayout = findFragmentLayout();
+ if (mFragmentLayout != null) {
+ return VIEW_INCLUDE;
+ }
+ } else {
+ mFragmentLayout = null;
+ }
+
+ return name;
+ }
+
+ @Override
public String getAttributeValue(String namespace, String localName) {
+ if (localName.equals(ATTR_LAYOUT) && mFragmentLayout != null) {
+ return mFragmentLayout;
+ }
+
String value = super.getAttributeValue(namespace, localName);
// on the fly convert match_parent to fill_parent for compatibility with older
@@ -76,4 +114,58 @@ public class ContextPullParser extends KXmlParser implements ILayoutPullParser {
return value;
}
+
+ /**
+ * This method determines whether the {@code <fragment>} tag in the current parsing
+ * context has been configured with a layout to render at designtime. If so,
+ * it returns the resource name of the layout, and if not, returns null.
+ */
+ private String findFragmentLayout() {
+ try {
+ if (!isEmptyElementTag()) {
+ // We need to look inside the <fragment> tag to see
+ // if it contains a comment which indicates a fragment
+ // to be rendered.
+ String file = AdtPlugin.readFile(mFile);
+
+ int line = getLineNumber() - 1;
+ int column = getColumnNumber() - 1;
+ int offset = 0;
+ int currentLine = 0;
+ int length = file.length();
+ while (currentLine < line && offset < length) {
+ int next = file.indexOf('\n', offset);
+ if (next == -1) {
+ break;
+ }
+
+ currentLine++;
+ offset = next + 1;
+ }
+ if (currentLine == line) {
+ offset += column;
+ if (offset < length) {
+ offset = file.indexOf('<', offset);
+ if (offset != -1 && file.startsWith(COMMENT_PREFIX, offset)) {
+ // The fragment tag contains a comment
+ int end = file.indexOf(COMMENT_SUFFIX, offset);
+ if (end != -1) {
+ String commentText = file.substring(
+ offset + COMMENT_PREFIX.length(), end);
+ String l = LayoutMetadata.getProperty(KEY_FRAGMENT_LAYOUT,
+ commentText);
+ if (l != null) {
+ return l;
+ }
+ }
+ }
+ }
+ }
+ }
+ } catch (XmlPullParserException e) {
+ AdtPlugin.log(e, null);
+ }
+
+ return null;
+ }
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ProjectCallback.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ProjectCallback.java
index c3698fd..c71005c 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ProjectCallback.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ProjectCallback.java
@@ -34,6 +34,7 @@ import com.android.ide.common.rendering.api.ResourceReference;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.ide.common.rendering.api.Result;
import com.android.ide.common.rendering.legacy.LegacyCallback;
+import com.android.ide.common.resources.ResourceResolver;
import com.android.ide.eclipse.adt.AdtConstants;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.internal.editors.layout.gle2.LayoutMetadata;
@@ -47,7 +48,12 @@ import com.android.sdklib.xml.ManifestData;
import com.android.util.Pair;
import org.eclipse.core.resources.IProject;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
@@ -58,7 +64,7 @@ import java.util.TreeSet;
/**
* Loader for Android Project class in order to use them in the layout editor.
* <p/>This implements {@link IProjectCallback} for the old and new API through
- * {@link ILegacyCallback}
+ * {@link LegacyCallback}
*/
public final class ProjectCallback extends LegacyCallback {
private final HashMap<String, Class<?>> mLoadedClasses = new HashMap<String, Class<?>>();
@@ -75,7 +81,7 @@ public final class ProjectCallback extends LegacyCallback {
private String mLayoutName;
private ILayoutPullParser mLayoutEmbeddedParser;
-
+ private ResourceResolver mResourceResolver;
/**
* Creates a new {@link ProjectCallback} to be used with the layout lib.
@@ -396,15 +402,51 @@ public final class ProjectCallback extends LegacyCallback {
}
public ILayoutPullParser getParser(String layoutName) {
- if (layoutName.equals(mLayoutName)) {
- return mLayoutEmbeddedParser;
+ // Try to compute the ResourceValue for this layout since layoutlib
+ // must be an older version which doesn't pass the value:
+ if (mResourceResolver != null) {
+ ResourceValue value = mResourceResolver.getProjectResource(ResourceType.LAYOUT,
+ layoutName);
+ if (value != null) {
+ return getParser(value);
+ }
}
- return null;
+ return getParser(layoutName, null);
}
public ILayoutPullParser getParser(ResourceValue layoutResource) {
- return getParser(layoutResource.getName());
+ return getParser(layoutResource.getName(),
+ new File(layoutResource.getValue()));
+ }
+
+ private ILayoutPullParser getParser(String layoutName, File xml) {
+ if (layoutName.equals(mLayoutName)) {
+ ILayoutPullParser parser = mLayoutEmbeddedParser;
+ // The parser should only be used once!! If it is included more than once,
+ // subsequent includes should just use a plain pull parser that is not tied
+ // to the XML model
+ mLayoutEmbeddedParser = null;
+ return parser;
+ }
+
+ // For included layouts, create a ContextPullParser such that we get the
+ // layout editor behavior in included layouts as well - which for example
+ // replaces <fragment> tags with <include>.
+ if (xml != null && xml.isFile()) {
+ ContextPullParser parser = new ContextPullParser(this, xml);
+ try {
+ parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
+ parser.setInput(new FileInputStream(xml), "UTF-8"); //$NON-NLS-1$
+ return parser;
+ } catch (XmlPullParserException e) {
+ AdtPlugin.log(e, null);
+ } catch (FileNotFoundException e) {
+ // Shouldn't happen since we check isFile() above
+ }
+ }
+
+ return null;
}
public Object getAdapterItemValue(ResourceReference adapterView, Object adapterCookie,
@@ -543,4 +585,13 @@ public final class ProjectCallback extends LegacyCallback {
return binding;
}
+
+ /**
+ * Sets the {@link ResourceResolver} to be used when looking up resources
+ *
+ * @param resolver the resolver to use
+ */
+ public void setResourceResolver(ResourceResolver resolver) {
+ mResourceResolver = resolver;
+ }
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java
index 5d0f5b6..e3d484d 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GraphicalEditorPart.java
@@ -220,16 +220,10 @@ public class GraphicalEditorPart extends EditorPart
private Map<ResourceType, Map<String, ResourceValue>> mConfiguredProjectRes;
private ProjectCallback mProjectCallback;
private boolean mNeedsRecompute = false;
-
private TargetListener mTargetListener;
-
private ConfigListener mConfigListener;
private ResourceResolver mResourceResolver;
-
private ReloadListener mReloadListener;
-
- private boolean mUseExplodeMode;
-
private int mMinSdkVersion;
private int mTargetSdkVersion;
private LayoutActionBar mActionBar;
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutMetadata.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutMetadata.java
index d2c4985..906a2ec 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutMetadata.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/LayoutMetadata.java
@@ -98,22 +98,7 @@ public class LayoutMetadata {
Node comment = findComment(node);
if (comment != null) {
String text = comment.getNodeValue();
- assert text.startsWith(COMMENT_PROLOGUE);
- String valuesString = text.substring(COMMENT_PROLOGUE.length());
- String[] values = valuesString.split(","); //$NON-NLS-1$
- if (values.length == 1) {
- valuesString = values[0].trim();
- if (valuesString.indexOf('\n') != -1) {
- values = valuesString.split("\n"); //$NON-NLS-1$
- }
- }
- String target = name + '=';
- for (int j = 0; j < values.length; j++) {
- String value = values[j].trim();
- if (value.startsWith(target)) {
- return value.substring(target.length()).trim();
- }
- }
+ return getProperty(name, text);
}
return null;
@@ -125,6 +110,33 @@ public class LayoutMetadata {
}
/**
+ * Returns the given property specified in the given XML comment
+ *
+ * @param name the name of the property to look up
+ * @param text the comment text for an XML node
+ * @return the value stored with the given node and name, or null
+ */
+ public static String getProperty(String name, String text) {
+ assert text.startsWith(COMMENT_PROLOGUE);
+ String valuesString = text.substring(COMMENT_PROLOGUE.length());
+ String[] values = valuesString.split(","); //$NON-NLS-1$
+ if (values.length == 1) {
+ valuesString = values[0].trim();
+ if (valuesString.indexOf('\n') != -1) {
+ values = valuesString.split("\n"); //$NON-NLS-1$
+ }
+ }
+ String target = name + '=';
+ for (int j = 0; j < values.length; j++) {
+ String value = values[j].trim();
+ if (value.startsWith(target)) {
+ return value.substring(target.length()).trim();
+ }
+ }
+ return null;
+ }
+
+ /**
* Sets the given property of the given DOM node to a given value, or if null clears
* the property.
*
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 36cea84..a03d038 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
@@ -320,7 +320,7 @@ public class RenderService {
// as it's what IXmlPullParser.getParser(String) will receive.
String queryLayoutName = mEditor.getLayoutResourceName();
mProjectCallback.setLayoutParser(queryLayoutName, modelParser);
- topParser = new ContextPullParser(mProjectCallback);
+ topParser = new ContextPullParser(mProjectCallback, layoutFile);
topParser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
topParser.setInput(new FileInputStream(layoutFile), "UTF-8"); //$NON-NLS-1$
} catch (XmlPullParserException e) {
@@ -376,6 +376,7 @@ public class RenderService {
try {
mProjectCallback.setLogger(mLogger);
+ mProjectCallback.setResourceResolver(mResourceResolver);
return mLayoutLib.createSession(params);
} catch (RuntimeException t) {
// Exceptions from the bridge
@@ -383,6 +384,7 @@ public class RenderService {
throw t;
} finally {
mProjectCallback.setLogger(null);
+ mProjectCallback.setResourceResolver(null);
}
}
@@ -482,6 +484,7 @@ public class RenderService {
RenderSession session = null;
try {
mProjectCallback.setLogger(mLogger);
+ mProjectCallback.setResourceResolver(mResourceResolver);
session = mLayoutLib.createSession(params);
if (session.getResult().isSuccess()) {
assert session.getRootViews().size() == 1;
@@ -506,6 +509,7 @@ public class RenderService {
throw t;
} finally {
mProjectCallback.setLogger(null);
+ mProjectCallback.setResourceResolver(null);
if (session != null) {
session.dispose();
}