am 4e27221d: Merge "Support databinding in listitem layouts." into mnc-ub-dev
* commit '4e27221d49151ba91af59029659e666fa756b645': Support databinding in listitem layouts.
This commit is contained in:
@@ -401,7 +401,7 @@ public final class BridgeResources extends Resources {
|
|||||||
if (xml.isFile()) {
|
if (xml.isFile()) {
|
||||||
// we need to create a pull parser around the layout XML file, and then
|
// we need to create a pull parser around the layout XML file, and then
|
||||||
// give that to our XmlBlockParser
|
// give that to our XmlBlockParser
|
||||||
parser = ParserFactory.create(xml);
|
parser = ParserFactory.create(xml, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ public final class BridgeInflater extends LayoutInflater {
|
|||||||
File f = new File(value.getValue());
|
File f = new File(value.getValue());
|
||||||
if (f.isFile()) {
|
if (f.isFile()) {
|
||||||
try {
|
try {
|
||||||
XmlPullParser parser = ParserFactory.create(f);
|
XmlPullParser parser = ParserFactory.create(f, true);
|
||||||
|
|
||||||
BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser(
|
BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser(
|
||||||
parser, bridgeContext, value.isFramework());
|
parser, bridgeContext, value.isFramework());
|
||||||
|
|||||||
@@ -436,7 +436,7 @@ public final class BridgeContext extends Context {
|
|||||||
// we need to create a pull parser around the layout XML file, and then
|
// we need to create a pull parser around the layout XML file, and then
|
||||||
// give that to our XmlBlockParser
|
// give that to our XmlBlockParser
|
||||||
try {
|
try {
|
||||||
XmlPullParser parser = ParserFactory.create(xml);
|
XmlPullParser parser = ParserFactory.create(xml, true);
|
||||||
|
|
||||||
// set the resource ref to have correct view cookies
|
// set the resource ref to have correct view cookies
|
||||||
mBridgeInflater.setResourceReference(resource);
|
mBridgeInflater.setResourceReference(resource);
|
||||||
|
|||||||
@@ -0,0 +1,378 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 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.android.layoutlib.bridge.impl;
|
||||||
|
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
|
import android.annotation.Nullable;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A wrapper around XmlPullParser that can peek forward to inspect if the file is a data-binding
|
||||||
|
* layout and some parts need to be stripped.
|
||||||
|
*/
|
||||||
|
public class LayoutParserWrapper implements XmlPullParser {
|
||||||
|
|
||||||
|
// Data binding constants.
|
||||||
|
private static final String TAG_LAYOUT = "layout";
|
||||||
|
private static final String TAG_DATA = "data";
|
||||||
|
private static final String DEFAULT = "default=";
|
||||||
|
|
||||||
|
private final XmlPullParser mDelegate;
|
||||||
|
|
||||||
|
// Storage for peeked values.
|
||||||
|
private boolean mPeeked;
|
||||||
|
private int mEventType;
|
||||||
|
private int mDepth;
|
||||||
|
private int mNext;
|
||||||
|
private List<Attribute> mAttributes;
|
||||||
|
private String mText;
|
||||||
|
private String mName;
|
||||||
|
|
||||||
|
// Used to end the document before the actual parser ends.
|
||||||
|
private int mFinalDepth = -1;
|
||||||
|
private boolean mEndNow;
|
||||||
|
|
||||||
|
public LayoutParserWrapper(XmlPullParser delegate) {
|
||||||
|
mDelegate = delegate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public LayoutParserWrapper peekTillLayoutStart() throws IOException, XmlPullParserException {
|
||||||
|
final int STATE_LAYOUT_NOT_STARTED = 0; // <layout> tag not encountered yet.
|
||||||
|
final int STATE_ROOT_NOT_STARTED = 1; // the main view root not found yet.
|
||||||
|
final int STATE_INSIDE_DATA = 2; // START_TAG for <data> found, but not END_TAG.
|
||||||
|
|
||||||
|
int state = STATE_LAYOUT_NOT_STARTED;
|
||||||
|
int dataDepth = -1; // depth of the <data> tag. Should be two.
|
||||||
|
while (true) {
|
||||||
|
int peekNext = peekNext();
|
||||||
|
switch (peekNext) {
|
||||||
|
case START_TAG:
|
||||||
|
if (state == STATE_LAYOUT_NOT_STARTED) {
|
||||||
|
if (mName.equals(TAG_LAYOUT)) {
|
||||||
|
state = STATE_ROOT_NOT_STARTED;
|
||||||
|
} else {
|
||||||
|
return this; // no layout tag in the file.
|
||||||
|
}
|
||||||
|
} else if (state == STATE_ROOT_NOT_STARTED) {
|
||||||
|
if (mName.equals(TAG_DATA)) {
|
||||||
|
state = STATE_INSIDE_DATA;
|
||||||
|
dataDepth = mDepth;
|
||||||
|
} else {
|
||||||
|
mFinalDepth = mDepth;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case END_TAG:
|
||||||
|
if (state == STATE_INSIDE_DATA) {
|
||||||
|
if (mDepth <= dataDepth) {
|
||||||
|
state = STATE_ROOT_NOT_STARTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case END_DOCUMENT:
|
||||||
|
// No layout start found.
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
// consume the peeked tag.
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int peekNext() throws IOException, XmlPullParserException {
|
||||||
|
if (mPeeked) {
|
||||||
|
return mNext;
|
||||||
|
}
|
||||||
|
mEventType = mDelegate.getEventType();
|
||||||
|
mNext = mDelegate.next();
|
||||||
|
if (mEventType == START_TAG) {
|
||||||
|
int count = mDelegate.getAttributeCount();
|
||||||
|
mAttributes = count > 0 ? new ArrayList<Attribute>(count) :
|
||||||
|
Collections.<Attribute>emptyList();
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
mAttributes.add(new Attribute(mDelegate.getAttributeNamespace(i),
|
||||||
|
mDelegate.getAttributeName(i), mDelegate.getAttributeValue(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mDepth = mDelegate.getDepth();
|
||||||
|
mText = mDelegate.getText();
|
||||||
|
mName = mDelegate.getName();
|
||||||
|
mPeeked = true;
|
||||||
|
return mNext;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reset() {
|
||||||
|
mAttributes = null;
|
||||||
|
mText = null;
|
||||||
|
mName = null;
|
||||||
|
mPeeked = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int next() throws XmlPullParserException, IOException {
|
||||||
|
int returnValue;
|
||||||
|
int depth;
|
||||||
|
if (mPeeked) {
|
||||||
|
returnValue = mNext;
|
||||||
|
depth = mDepth;
|
||||||
|
reset();
|
||||||
|
} else if (mEndNow) {
|
||||||
|
return END_DOCUMENT;
|
||||||
|
} else {
|
||||||
|
returnValue = mDelegate.next();
|
||||||
|
depth = getDepth();
|
||||||
|
}
|
||||||
|
if (returnValue == END_TAG && depth <= mFinalDepth) {
|
||||||
|
mEndNow = true;
|
||||||
|
}
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getEventType() throws XmlPullParserException {
|
||||||
|
return mPeeked ? mEventType : mDelegate.getEventType();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getDepth() {
|
||||||
|
return mPeeked ? mDepth : mDelegate.getDepth();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return mPeeked ? mName : mDelegate.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getText() {
|
||||||
|
return mPeeked ? mText : mDelegate.getText();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAttributeValue(@Nullable String namespace, String name) {
|
||||||
|
String returnValue = null;
|
||||||
|
if (mPeeked) {
|
||||||
|
if (mAttributes == null) {
|
||||||
|
if (mEventType != START_TAG) {
|
||||||
|
throw new IndexOutOfBoundsException("getAttributeValue() called when not at " +
|
||||||
|
"START_TAG.");
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (Attribute attribute : mAttributes) {
|
||||||
|
//noinspection StringEquality for nullness check.
|
||||||
|
if (attribute.name.equals(name) && (attribute.namespace == namespace ||
|
||||||
|
attribute.namespace != null && attribute.namespace.equals(namespace))) {
|
||||||
|
returnValue = attribute.value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
returnValue = mDelegate.getAttributeValue(namespace, name);
|
||||||
|
}
|
||||||
|
// Check if the value is bound via data-binding, if yes get the default value.
|
||||||
|
if (returnValue != null && mFinalDepth >= 0 && returnValue.startsWith("@{")) {
|
||||||
|
// TODO: Improve the detection of default keyword.
|
||||||
|
int i = returnValue.lastIndexOf(DEFAULT);
|
||||||
|
return i > 0 ? returnValue.substring(i + DEFAULT.length(), returnValue.length() - 1)
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class Attribute {
|
||||||
|
@Nullable
|
||||||
|
public final String namespace;
|
||||||
|
public final String name;
|
||||||
|
public final String value;
|
||||||
|
|
||||||
|
public Attribute(@Nullable String namespace, String name, String value) {
|
||||||
|
this.namespace = namespace;
|
||||||
|
this.name = name;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not affected by peeking.
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFeature(String s, boolean b) throws XmlPullParserException {
|
||||||
|
mDelegate.setFeature(s, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setProperty(String s, Object o) throws XmlPullParserException {
|
||||||
|
mDelegate.setProperty(s, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setInput(InputStream inputStream, String s) throws XmlPullParserException {
|
||||||
|
mDelegate.setInput(inputStream, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setInput(Reader reader) throws XmlPullParserException {
|
||||||
|
mDelegate.setInput(reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getInputEncoding() {
|
||||||
|
return mDelegate.getInputEncoding();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNamespace(String s) {
|
||||||
|
return mDelegate.getNamespace(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPositionDescription() {
|
||||||
|
return mDelegate.getPositionDescription();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getLineNumber() {
|
||||||
|
return mDelegate.getLineNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNamespace() {
|
||||||
|
return mDelegate.getNamespace();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getColumnNumber() {
|
||||||
|
return mDelegate.getColumnNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- We don't care much about the methods that follow.
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void require(int i, String s, String s1) throws XmlPullParserException, IOException {
|
||||||
|
throw new UnsupportedOperationException("Only few parser methods are supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getFeature(String s) {
|
||||||
|
throw new UnsupportedOperationException("Only few parser methods are supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void defineEntityReplacementText(String s, String s1) throws XmlPullParserException {
|
||||||
|
throw new UnsupportedOperationException("Only few parser methods are supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getProperty(String s) {
|
||||||
|
throw new UnsupportedOperationException("Only few parser methods are supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int nextToken() throws XmlPullParserException, IOException {
|
||||||
|
throw new UnsupportedOperationException("Only few parser methods are supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNamespaceCount(int i) throws XmlPullParserException {
|
||||||
|
throw new UnsupportedOperationException("Only few parser methods are supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNamespacePrefix(int i) throws XmlPullParserException {
|
||||||
|
throw new UnsupportedOperationException("Only few parser methods are supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getNamespaceUri(int i) throws XmlPullParserException {
|
||||||
|
throw new UnsupportedOperationException("Only few parser methods are supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWhitespace() throws XmlPullParserException {
|
||||||
|
throw new UnsupportedOperationException("Only few parser methods are supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public char[] getTextCharacters(int[] ints) {
|
||||||
|
throw new UnsupportedOperationException("Only few parser methods are supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPrefix() {
|
||||||
|
throw new UnsupportedOperationException("Only few parser methods are supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmptyElementTag() throws XmlPullParserException {
|
||||||
|
throw new UnsupportedOperationException("Only few parser methods are supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getAttributeCount() {
|
||||||
|
throw new UnsupportedOperationException("Only few parser methods are supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAttributeNamespace(int i) {
|
||||||
|
throw new UnsupportedOperationException("Only few parser methods are supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAttributeName(int i) {
|
||||||
|
throw new UnsupportedOperationException("Only few parser methods are supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAttributePrefix(int i) {
|
||||||
|
throw new UnsupportedOperationException("Only few parser methods are supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAttributeType(int i) {
|
||||||
|
throw new UnsupportedOperationException("Only few parser methods are supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAttributeDefault(int i) {
|
||||||
|
throw new UnsupportedOperationException("Only few parser methods are supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getAttributeValue(int i) {
|
||||||
|
throw new UnsupportedOperationException("Only few parser methods are supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String nextText() throws XmlPullParserException, IOException {
|
||||||
|
throw new UnsupportedOperationException("Only few parser methods are supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int nextTag() throws XmlPullParserException, IOException {
|
||||||
|
throw new UnsupportedOperationException("Only few parser methods are supported.");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -53,24 +53,35 @@ public class ParserFactory {
|
|||||||
@NonNull
|
@NonNull
|
||||||
public static XmlPullParser create(@NonNull File f)
|
public static XmlPullParser create(@NonNull File f)
|
||||||
throws XmlPullParserException, FileNotFoundException {
|
throws XmlPullParserException, FileNotFoundException {
|
||||||
InputStream stream = new FileInputStream(f);
|
return create(f, false);
|
||||||
return create(stream, f.getName(), f.length());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static XmlPullParser create(@NonNull File f, boolean isLayout)
|
||||||
|
throws XmlPullParserException, FileNotFoundException {
|
||||||
|
InputStream stream = new FileInputStream(f);
|
||||||
|
return create(stream, f.getName(), f.length(), isLayout);
|
||||||
|
}
|
||||||
@NonNull
|
@NonNull
|
||||||
public static XmlPullParser create(@NonNull InputStream stream, @Nullable String name)
|
public static XmlPullParser create(@NonNull InputStream stream, @Nullable String name)
|
||||||
throws XmlPullParserException {
|
throws XmlPullParserException {
|
||||||
return create(stream, name, -1);
|
return create(stream, name, -1, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private static XmlPullParser create(@NonNull InputStream stream, @Nullable String name,
|
private static XmlPullParser create(@NonNull InputStream stream, @Nullable String name,
|
||||||
long size) throws XmlPullParserException {
|
long size, boolean isLayout) throws XmlPullParserException {
|
||||||
XmlPullParser parser = instantiateParser(name);
|
XmlPullParser parser = instantiateParser(name);
|
||||||
|
|
||||||
stream = readAndClose(stream, name, size);
|
stream = readAndClose(stream, name, size);
|
||||||
|
|
||||||
parser.setInput(stream, ENCODING);
|
parser.setInput(stream, ENCODING);
|
||||||
|
if (isLayout) {
|
||||||
|
try {
|
||||||
|
return new LayoutParserWrapper(parser).peekTillLayoutStart();
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new XmlPullParserException(null, parser, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
return parser;
|
return parser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,183 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2015 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.android.layoutlib.bridge.impl;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.kxml2.io.KXmlParser;
|
||||||
|
import org.xmlpull.v1.XmlPullParser;
|
||||||
|
import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
|
import java.io.StringReader;
|
||||||
|
|
||||||
|
import static com.android.SdkConstants.NS_RESOURCES;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotSame;
|
||||||
|
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
|
||||||
|
import static org.xmlpull.v1.XmlPullParser.END_TAG;
|
||||||
|
import static org.xmlpull.v1.XmlPullParser.START_TAG;
|
||||||
|
|
||||||
|
|
||||||
|
public class LayoutParserWrapperTest {
|
||||||
|
@Test
|
||||||
|
@SuppressWarnings("StatementWithEmptyBody") // some for loops need to be empty statements.
|
||||||
|
public void testDataBindingLayout() throws Exception {
|
||||||
|
LayoutParserWrapper parser = getParserFromString(sDataBindingLayout);
|
||||||
|
parser.peekTillLayoutStart();
|
||||||
|
assertEquals("Expected START_TAG", START_TAG, parser.next());
|
||||||
|
assertEquals("RelativeLayout", parser.getName());
|
||||||
|
for (int next = parser.next(); next != START_TAG && next != END_DOCUMENT;
|
||||||
|
next = parser.next());
|
||||||
|
assertEquals("Expected START_TAG", START_TAG, parser.getEventType());
|
||||||
|
assertEquals("TextView", parser.getName());
|
||||||
|
assertEquals("layout_width incorrect for first text view.", "wrap_content",
|
||||||
|
parser.getAttributeValue(NS_RESOURCES, "layout_width"));
|
||||||
|
// Ensure that data-binding part is stripped.
|
||||||
|
assertEquals("Bound attribute android:text incorrect", "World",
|
||||||
|
parser.getAttributeValue(NS_RESOURCES, "text"));
|
||||||
|
assertEquals("resource attribute 'id' for first text view incorrect.", "@+id/first",
|
||||||
|
parser.getAttributeValue(NS_RESOURCES, "id"));
|
||||||
|
for (int next = parser.next();
|
||||||
|
(next != END_TAG || !"RelativeLayout".equals(parser.getName())) && next != END_DOCUMENT;
|
||||||
|
next = parser.next());
|
||||||
|
assertNotSame("Unexpected end of document", END_DOCUMENT, parser.getEventType());
|
||||||
|
assertEquals("Document didn't end when expected.", END_DOCUMENT, parser.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SuppressWarnings("StatementWithEmptyBody")
|
||||||
|
public void testNonDataBindingLayout() throws Exception {
|
||||||
|
LayoutParserWrapper parser = getParserFromString(sNonDataBindingLayout);
|
||||||
|
parser.peekTillLayoutStart();
|
||||||
|
assertEquals("Expected START_TAG", START_TAG, parser.next());
|
||||||
|
assertEquals("RelativeLayout", parser.getName());
|
||||||
|
for (int next = parser.next(); next != START_TAG && next != END_DOCUMENT;
|
||||||
|
next = parser.next());
|
||||||
|
assertEquals("Expected START_TAG", START_TAG, parser.getEventType());
|
||||||
|
assertEquals("TextView", parser.getName());
|
||||||
|
assertEquals("layout_width incorrect for first text view.", "wrap_content",
|
||||||
|
parser.getAttributeValue(NS_RESOURCES, "layout_width"));
|
||||||
|
// Ensure that value isn't modified.
|
||||||
|
assertEquals("Bound attribute android:text incorrect", "@{user.firstName,default=World}",
|
||||||
|
parser.getAttributeValue(NS_RESOURCES, "text"));
|
||||||
|
assertEquals("resource attribute 'id' for first text view incorrect.", "@+id/first",
|
||||||
|
parser.getAttributeValue(NS_RESOURCES, "id"));
|
||||||
|
for (int next = parser.next();
|
||||||
|
(next != END_TAG || !"RelativeLayout".equals(parser.getName())) && next != END_DOCUMENT;
|
||||||
|
next = parser.next());
|
||||||
|
assertNotSame("Unexpected end of document", END_DOCUMENT, parser.getEventType());
|
||||||
|
assertEquals("Document didn't end when expected.", END_DOCUMENT, parser.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static LayoutParserWrapper getParserFromString(String layoutContent) throws
|
||||||
|
XmlPullParserException {
|
||||||
|
XmlPullParser parser = new KXmlParser();
|
||||||
|
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
|
||||||
|
parser.setInput(new StringReader(layoutContent));
|
||||||
|
return new LayoutParserWrapper(parser);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final String sDataBindingLayout =
|
||||||
|
//language=XML
|
||||||
|
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
|
||||||
|
"<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
|
||||||
|
" xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n" +
|
||||||
|
" xmlns:tools=\"http://schemas.android.com/tools\"\n" +
|
||||||
|
" tools:context=\".MainActivity\"\n" +
|
||||||
|
" tools:showIn=\"@layout/activity_main\">\n" +
|
||||||
|
"\n" +
|
||||||
|
" <data>\n" +
|
||||||
|
"\n" +
|
||||||
|
" <variable\n" +
|
||||||
|
" name=\"user\"\n" +
|
||||||
|
" type=\"com.example.User\" />\n" +
|
||||||
|
" <variable\n" +
|
||||||
|
" name=\"activity\"\n" +
|
||||||
|
" type=\"com.example.MainActivity\" />\n" +
|
||||||
|
" </data>\n" +
|
||||||
|
"\n" +
|
||||||
|
" <RelativeLayout\n" +
|
||||||
|
" android:layout_width=\"match_parent\"\n" +
|
||||||
|
" android:layout_height=\"match_parent\"\n" +
|
||||||
|
" android:paddingBottom=\"@dimen/activity_vertical_margin\"\n" +
|
||||||
|
" android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n" +
|
||||||
|
" android:paddingRight=\"@dimen/activity_horizontal_margin\"\n" +
|
||||||
|
" android:paddingTop=\"@dimen/activity_vertical_margin\"\n" +
|
||||||
|
" app:layout_behavior=\"@string/appbar_scrolling_view_behavior\"\n" +
|
||||||
|
" >\n" +
|
||||||
|
"\n" +
|
||||||
|
" <TextView\n" +
|
||||||
|
" android:id=\"@+id/first\"\n" +
|
||||||
|
" android:layout_width=\"wrap_content\"\n" +
|
||||||
|
" android:layout_alignParentStart=\"true\"\n" +
|
||||||
|
" android:layout_alignParentLeft=\"true\"\n" +
|
||||||
|
" android:layout_height=\"wrap_content\"\n" +
|
||||||
|
" android:text=\"@{user.firstName,default=World}\" />\n" +
|
||||||
|
"\n" +
|
||||||
|
" <TextView\n" +
|
||||||
|
" android:id=\"@+id/last\"\n" +
|
||||||
|
" android:layout_width=\"wrap_content\"\n" +
|
||||||
|
" android:layout_height=\"wrap_content\"\n" +
|
||||||
|
" android:layout_toEndOf=\"@id/first\"\n" +
|
||||||
|
" android:layout_toRightOf=\"@id/first\"\n" +
|
||||||
|
" android:text=\"@{user.lastName,default=Hello}\" />\n" +
|
||||||
|
"\n" +
|
||||||
|
" <Button\n" +
|
||||||
|
" android:layout_width=\"wrap_content\"\n" +
|
||||||
|
" android:layout_height=\"wrap_content\"\n" +
|
||||||
|
" android:layout_below=\"@id/last\"\n" +
|
||||||
|
" android:text=\"Submit\"\n" +
|
||||||
|
" android:onClick=\"@{activity.onClick}\"/>\n" +
|
||||||
|
" </RelativeLayout>\n" +
|
||||||
|
"</layout>";
|
||||||
|
|
||||||
|
private static final String sNonDataBindingLayout =
|
||||||
|
//language=XML
|
||||||
|
"<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
|
||||||
|
" xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n" +
|
||||||
|
" android:layout_width=\"match_parent\"\n" +
|
||||||
|
" android:layout_height=\"match_parent\"\n" +
|
||||||
|
" android:paddingBottom=\"@dimen/activity_vertical_margin\"\n" +
|
||||||
|
" android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n" +
|
||||||
|
" android:paddingRight=\"@dimen/activity_horizontal_margin\"\n" +
|
||||||
|
" android:paddingTop=\"@dimen/activity_vertical_margin\"\n" +
|
||||||
|
" app:layout_behavior=\"@string/appbar_scrolling_view_behavior\"\n" +
|
||||||
|
">\n" +
|
||||||
|
"\n" +
|
||||||
|
" <TextView\n" +
|
||||||
|
" android:id=\"@+id/first\"\n" +
|
||||||
|
" android:layout_width=\"wrap_content\"\n" +
|
||||||
|
" android:layout_alignParentStart=\"true\"\n" +
|
||||||
|
" android:layout_alignParentLeft=\"true\"\n" +
|
||||||
|
" android:layout_height=\"wrap_content\"\n" +
|
||||||
|
" android:text=\"@{user.firstName,default=World}\" />\n" +
|
||||||
|
"\n" +
|
||||||
|
" <TextView\n" +
|
||||||
|
" android:id=\"@+id/last\"\n" +
|
||||||
|
" android:layout_width=\"wrap_content\"\n" +
|
||||||
|
" android:layout_height=\"wrap_content\"\n" +
|
||||||
|
" android:layout_toEndOf=\"@id/first\"\n" +
|
||||||
|
" android:layout_toRightOf=\"@id/first\"\n" +
|
||||||
|
" android:text=\"@{user.lastName,default=Hello}\" />\n" +
|
||||||
|
"\n" +
|
||||||
|
" <Button\n" +
|
||||||
|
" android:layout_width=\"wrap_content\"\n" +
|
||||||
|
" android:layout_height=\"wrap_content\"\n" +
|
||||||
|
" android:layout_below=\"@id/last\"\n" +
|
||||||
|
" android:text=\"Submit\"\n" +
|
||||||
|
" android:onClick=\"@{activity.onClick}\"/>\n" +
|
||||||
|
"</RelativeLayout>";
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user